Compare commits

...

1610 Commits

Author SHA1 Message Date
Nathan Voxland
5ad741c0d2 Cleaning up code 2026-04-01 13:58:39 -05:00
Nathan Voxland
69570bc65f Cleaning up code 2026-03-31 20:15:55 -05:00
Nathan Voxland
b719615aa6 Cleaning up code 2026-03-31 17:09:51 -05:00
Nathan Voxland
afcc49f6f6 Refactor MQ test init: use :mq initialization step instead of is-test? checks
Replace scattered is-test? checks at var definition time with a proper
:mq initialization step in the test startup flow. This mirrors how
production initializes MQ via MqInit in startup/run-startup-logic!.

The :mq step:
- Loads driver.init (so def-listener! namespaces are loaded)
- Calls mq.init/init-for-tests! which sets sync backends, disables
  publish buffering, and registers all listeners

Also:
- Reverts var defaults to production values (appdb backends, 100ms buffer)
- Reverts def-listener! to lazy registration (no eager call)
- Restores with-sync-mq to use fresh *listeners* atom
- Removes all [TZ-DEBUG] diagnostic traces
- :db initialization depends on :mq

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:00:26 -05:00
Nathan Voxland
d12184f4a0 Fix eager listener registration: call multimethod, not method map lookup
The eager registration code used ((methods def-listener*) channel) which
returns the method fn from the methods map but doesn't invoke it. Changed
to (def-listener* channel) which dispatches through the multimethod and
actually calls the registration function.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:08:09 -05:00
Nathan Voxland
bde8a43aeb Add tracing to :db init to verify driver.init loading
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:27:56 -05:00
Nathan Voxland
76f8cb6ce3 Don't rebind *listeners* to empty atom in with-sync-mq
with-sync-mq was binding *listeners* to (atom {}), which created a
fresh empty atom that shadowed the root atom where listeners were
eagerly registered at def-listener! time. Since eftest propagates
bindings to worker threads, parallel tests running on threads spawned
within a with-sync-mq scope would see the empty atom and fail to find
any listeners.

Fix: stop rebinding *listeners*. Listeners are eagerly registered into
the root atom at namespace load time and should remain globally visible.
with-sync-mq still binds backends and buffer settings as needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 12:55:18 -05:00
Nathan Voxland
31840a1a31 Add atom identity tracing to diagnose listener registration
Trace which *listeners* atom instance is used during registration vs
lookup to detect if a dynamic rebinding is causing listeners to be
registered in one atom but looked up in another.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 12:35:43 -05:00
Nathan Voxland
a5968cdf24 Load driver/init.clj during test :db initialization
The MQ listeners defined in driver_notifications.clj (e.g.
connection-pool-invalidated) are only loaded via driver/init.clj, which
is loaded via core/init.clj in production. Tests don't load core/init.clj,
so these listener namespaces are never required and the eager registration
from def-listener! never happens.

Fix: require driver.init during test :db initialization so the listener
namespaces get loaded and listeners are registered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:37:56 -05:00
Nathan Voxland
5bcdea9b51 Eagerly register MQ listeners at def-listener! time
def-listener! now immediately registers the listener when the namespace
loads, instead of deferring to register-listeners! called from MqInit.
This ensures listeners are available in test mode where MqInit never runs
(tests use initialize-if-needed!, not startup/run-startup-logic!).

register-listener! is idempotent so the production path (MqInit calling
register-listeners!) still works fine.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 10:37:11 -05:00
Nathan Voxland
8eafca6c74 Add tracing to invoke-listener! to diagnose missing listener
The sync backend publish fires but listener output never appears.
Adding trace to see if listener is registered or not.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:57:50 -05:00
Nathan Voxland
6adf7f2ef8 Default MQ backends to sync in test mode
Same issue as *publish-buffer-ms*: MqInit never runs in tests, so the
alter-var-root that sets backends to sync has no effect. Set defaults
at var definition time based on config/is-test?.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 08:59:56 -05:00
Nathan Voxland
2ea7960d5c Default *publish-buffer-ms* to 0 in test mode
MqInit never runs in tests (tests use initialize-if-needed!, not
run-startup-logic!), so the alter-var-root in the previous fix had
no effect. Instead, set the default value at var definition time
based on config/is-test?.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 01:26:49 -05:00
Nathan Voxland
66af12b9cd Add more MQ tracing to diagnose CI failures
Traces at buffered-publish!, transport/publish!, sync-backend/publish!,
and MqInit to understand why *publish-buffer-ms* is still 100 in CI
(meaning messages are buffered instead of delivered immediately).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 01:02:26 -05:00
Nathan Voxland
8171f24196 Debugging CI failures 2026-03-31 00:27:49 -05:00
Nathan Voxland
a86dffa344 Fix MQ topic messages silently dropped in test mode
In test mode, MqInit sets sync backends but leaves *publish-buffer-ms*
at its default of 100ms. This causes buffered-publish! to buffer messages
instead of delivering them immediately. Since start-publish-buffer-flush!
is never called in test mode, no background thread drains the buffer,
so topic messages are silently dropped.

This broke report-timezone change notifications — connection pools were
never invalidated when timezone changed, causing stale timezone sessions
on database connections. This manifested as timezone-shifted query results
across 28+ driver tests in CI.

Fix: set *publish-buffer-ms* to 0 in test init path so messages publish
immediately without buffering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:56:59 -05:00
Nathan Voxland
db09e70823 Debugging CI failures 2026-03-30 20:27:04 -05:00
Nathan Voxland
407f3bc2df Merge branch 'master' into persistent-queue 2026-03-29 18:22:27 -05:00
Fraser
e9b56f49b5 Allow Enterprise module to import from feature modules (#71468) 2026-03-29 16:26:56 +13:00
Fraser
307b2906b7 Fix module stats upload script (#71385) 2026-03-29 16:26:43 +13:00
Nathan Voxland
5b1181eba5 Fixed module setup 2026-03-28 01:40:24 -05:00
Nathan Voxland
1574a28b4f Fixed tests 2026-03-28 01:26:44 -05:00
lbrdnk
b8d3ac0869 Adjust search schemas (#71572) 2026-03-27 16:13:42 -07:00
Alexander Polyankin
ad4dfb41b1 Fix typo in transform database validation messages (#71596) 2026-03-27 22:34:25 +00:00
Nathan Voxland
ace1e034a2 Fixed tests 2026-03-27 15:50:33 -05:00
Nathan Voxland
9142569d91 Fixed tests 2026-03-27 14:58:23 -05:00
github-automation-metabase
38e28e0ec3 Fix pagerDurty workflow edge case (#71574)
Fix PagerDuty alert broken by single quote in issue title

Use jq --arg to safely construct the JSON payload instead of
interpolating user-controlled data directly into a shell string.
This prevents shell syntax errors when issue titles contain single
quotes or other special characters.

Removes the now-unnecessary 'Setting title' step that only escaped
double-quotes but left single quotes unhandled.
2026-03-27 20:52:32 +01:00
Nathan Voxland
30c6275dc5 Fixed tests 2026-03-27 14:05:41 -05:00
Nathan Voxland
0f2e7ea906 Fixed tests 2026-03-27 13:51:36 -05:00
Nathan Voxland
cff57cbbb5 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	enterprise/backend/test/metabase_enterprise/agent_api/api_test.clj
2026-03-27 13:38:08 -05:00
Edward Paget
655a3f6ac7 Move agent API tests from enterprise to OSS (#71456) 2026-03-27 18:30:00 +00:00
Nathan Voxland
62c13bb028 Fixed formatting 2026-03-27 13:16:24 -05:00
Chris Truter
3c968befff Improve model encapsulation with serialization bypass (#71553) 2026-03-27 20:11:07 +02:00
Nathan Voxland
8f7064e87f Fixing tests 2026-03-27 12:56:26 -05:00
Sloan Sparger
334ed1fe42 [Metabot] Hide metabot feedback buttons on non-hosted instances (#71539)
hide metabot feedback buttons on non-hosted instances
2026-03-27 12:53:02 -05:00
Sloan Sparger
8e79105b9b [Metabot] Temporary removal of analyze chart button on dashboard page (#71540)
temp removal of analyze chart button on dashboard page
2026-03-27 12:52:53 -05:00
Ryan Laurie
92cd3f6cbf Converts some tests to ts (#71520)
converts tests to ts
2026-03-27 11:23:51 -06:00
Noah Moss
7089932b89 Move slack connect tests over to oss + fix API routes (#71525)
* move slack connect tests over to oss and remove some references to the token

* remove EE routes, always use OSS

* simplify

* undo some of that simplification

* fix tests / lint

* Move one test back to EE since it tests slack-connect's interaction with SAML
2026-03-27 10:50:48 -04:00
Nathan Voxland
27e5f298d8 Fixing tests 2026-03-27 09:27:36 -05:00
Nicolò Pretto
c4a27f18d3 embedding-hub: preserve "Select data" state + reset next steps after changing data segregation strategy (#71368)
* move up the state to persist it across steps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: reopen create tenants step when changing segregation strategy

When the user changes the data segregation strategy after already
creating tenants, the create tenants step now correctly reopens
instead of skipping to summary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* address feedback

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 15:24:32 +01:00
Phoomparin Mano
811e4466b2 Update in-app JWT onboarding to use snippets instead of iframes (#70475)
* share the same snippets for onboarding flow

* use sdk-docs-snippets namespace

* sync snippets

* fix rspack config

* rspack config: use path

* rspack: simplify resolve aliases

* remove node_modules from react refresh

* add copy button

* cleanup codemirror styling

* future proof: allow importing tsx files as well

* fix eslint pattern

* chore: move eslint ignore

* test to simplify aliases

* add context to ttag strings

---------

Co-authored-by: Nicolò Pretto <info@npretto.com>
2026-03-27 15:24:18 +01:00
Jeff Bruemmer
48c41ec6c8 Docs metabot slack (#71526) 2026-03-27 10:02:47 -04:00
Oleksandr Solovyov
b93319ab57 metabot llm calls: tools are optional/maybe (#71555) 2026-03-27 13:25:04 +00:00
lbrdnk
31905eaba4 Add 60 to version-helpers.ts (#71480)
Update versionRequirements
2026-03-27 11:02:22 +01:00
Nicolò Pretto
a0a14a42d3 scroll to top on page change in admin settings (#71369)
* scroll to top on page change in admin settings

* make tests green

* switch to useRouter instead of hoc
2026-03-27 09:55:04 +01:00
lbrdnk
839784b50c Fix transform writing tools (#71100)
* Add needed capabilities

* Partly fix transforms-write ns

* Partial fix to python transforms

* Add tool prompts

* Cleanup native transforms

* Add parameter schema descriptions

* Python schemas adjustments

* Adjust tool prompts

* Cleanup

* Tests

* Add capabilities test

* tests

* cleanup

* cleanup

* mbql5 and tests

* tests

* tests

* tests

* feature sentinel

---------

Co-authored-by: Tyler Plude <tsplude@gmail.com>
2026-03-27 08:44:57 +01:00
Nemanja Glumac
e9bc4ac447 Notify Slack on cross-version test failures (#71491) 2026-03-27 08:16:10 +01:00
Chris Truter
7180c6ae4b Optimize transform target table backfill migrations (#71487)
Better safe than sorry, given recent problems with expensive migrations.
2026-03-27 06:49:07 +02:00
Nick Fitzpatrick
a57a1c0ab8 preserve navbar status in the url update at the end of handleQBInit (#71505) 2026-03-27 09:59:12 +05:30
Nick Fitzpatrick
bee30e6423 Uxw 3355 page titles not in sync with data studio tabs (#71401)
* Fixing page titles in Data Studio

* shuffling Library files around. Adding library page title to all library subpages
2026-03-27 09:50:52 +05:30
Nick Fitzpatrick
281aa0dc12 decrease font size in click behavior sidebar (#71519) 2026-03-27 09:48:40 +05:30
Nick Fitzpatrick
14bd0853f6 set line height to 'normal' for textareas (#71498) 2026-03-27 09:48:20 +05:30
Romeo Van Snick
8be374db14 Convert query builder redux store to ts (#71063)
* Convert query_builder reducers to js

* Convert query_builder selectors to ts

* Fix types

* Fix types

* Fix types

* Fix isResultDirty selector

* Fix selector

* Move selector tests to TS

* Move reducers-typed into reducers

* Fix types

* Fix types

* Fix object id parsing

* Fix more types

* Fix PKRowIndexmap types

* Make name for EDIT_SUMMARY consistent

* Fix hanging test
2026-03-27 13:59:05 +11:00
Nathan Voxland
c6dff735a9 Fixing tests 2026-03-26 18:13:35 -05:00
Alexander Polyankin
b7e1d1eff8 Serdes for cards, segments, measures, transforms - allow deserializing only with minimal required properties without computed ones (#71464) 2026-03-26 18:51:58 -04:00
github-automation-metabase
3dd4c46871 Auto-update documentation for master (#71533)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-26 18:49:20 -04:00
Noah Moss
e7ae8072ca Reorganization + consolidation of metabot system prompts (#71506)
* Reorganization + consolidation of metabot system prompts

* More reorganization

* More shared prompt files

* revert search changes included accidentally

* more organization

* Fix dialect resource paths in module drivers

Update llm-sql-dialect-resource defmethods to use correct metabot/prompts/dialects/ path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* share personality prompt for nlq profile

* bump ci

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-26 17:27:26 -04:00
Riley Thompson
483f2086dd Bump databricks jdbc driver to 3.3.1 (#71513)
* bump databricks jdbc

* trigger ci
2026-03-26 21:17:38 +00:00
Edward Paget
cb9c042404 Fix MCP tool dispatch to pass query params correctly per Ring spec (#71502)
invoke-agent-api-with-params was encoding GET/DELETE query params into
the URI string, but defendpoint reads from :query-params (a parsed
map) on the Ring request. The synthetic request never passes through
wrap-params middleware, so query params in the URI were silently
ignored.

Fix by moving the method-based dispatch into deliver-agent-api-response:
POST params go to :body, GET/DELETE params go to :query-params.
Remove invoke-agent-api-with-params which is no longer needed.
2026-03-26 15:49:09 -05:00
Anderson
1b26236cf1 Do not show JWT shared secret as plaintext after it is saved (#71165)
* Handle JWT shared secret as write-only after initial generation (#UXW-3300)

- Thread generated token through wizard state so AddEndpointStep displays
  the plaintext key without re-reading it from session properties
- FormSecretKey now recognises the backend obfuscated format (**********XX)
  and renders an empty input with 'Already set' placeholder and a
  'Regenerate key' button, rather than showing the masked value

* Add unit tests for FormSecretKey obfuscated value handling (#UXW-3300)

- Tests covering no-value, plaintext, and obfuscated backend secret states
- Verifies 'Already set' placeholder and button labels are correct per state
- Verifies confirmation modal uses caller-supplied title/body
- Verifies token regeneration clears obfuscated value

* Fix prettier formatting in FormSecretKey.tsx

* Update the way we obfuscate the key and handle it on the frontend

* Add be test, improve alert

* Fix ts

* discard unnecessary changes

* Remove section that displayed the JWT secret in embedding set up

* Fix e2e test

* Show dedicated modal when generating new JWT shared key

* Fix unit test

* Fix e2e tests

* Fix latest UI changes

* Address review comments

* Add loading state to secret key modal and assert obfuscated key in E2E test

* Read jwt-shared-secret from /api/setting instead of session-properties / Revert unneeded obfuscated? implementation

* Fix tests

* Replace reads of session properties with api settings to simplify component logic
2026-03-26 16:34:54 -03:00
Chris Truter
14ff22021e Support non-datetime migration ids in tests (#71471)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:03:02 +02:00
Nick Fitzpatrick
55df67b632 Update Value normalization / collapsing in ChartSettingInputNumeric.tsx (#71440) 2026-03-27 00:14:41 +05:30
Edward Paget
53b678bcd6 Flatten root-level :or/:and/:multi into flat object schemas for MCP clients (#71494)
* Flatten root-level :or/:and/:multi into flat object schemas for MCP clients

Only the outermost composite schemas are flattened — nested anyOf/allOf
within properties are preserved since LLM clients handle them fine.

- :and → :merge then deref (flattens the [:map {:encode/...}] pattern)
- :or → :union with optional-keys, then deref (merges branches)
- :multi → same as :or, extracts schemas from dispatch triples

Also updates construct_query and query tool descriptions to explain
which fields are mutually exclusive (table_id vs metric_id vs
continuation_token).

* Refactor flatten-root-schema to worklist with cycle detection

Replace the recursive flatten-root-schema with a two-phase approach:
collect-root-maps walks the root composite tree using an iterative
worklist, then flatten-root-schema merges the collected leaves.

This eliminates stack recursion (:or/:multi no longer call
flatten-root-schema on children) and replaces the fuel counter with
a seen set that precisely detects deref cycles. On cycle detection,
emit an empty :map (-> {"type":"object"}) as a safe fallback.

The worklist also fixes :and wrapping :or — both layers now flatten
correctly since all composite nodes are expanded uniformly.

Adds tests for deeply nested composites, nested composites within
properties (preserved as anyOf/allOf), and :multi root flattening.
2026-03-26 17:48:52 +00:00
Nathan Voxland
daaca9ef62 CI fixes 2026-03-26 12:30:15 -05:00
Cam Saul
6a15fee1c5 Test to prove #32068 is fixed 🔧 (#71382)
* Test to prove #32068 is fixed 🔧

* Whoops revert deliberate test breakage

* Simplify test
2026-03-26 16:43:44 +00:00
Nicolò Pretto
92c07ddea1 hide sample db from embedding onboarding picker (#71304)
* hide sample db from embedding onboarding picker

* simplify e2e

* let's see if ci is green

* remove useless line, this is always pg
2026-03-26 17:23:19 +01:00
Sébastien
3dd99b6494 Fixed flaky custom elements api <metabase-question> test (#71500) 2026-03-26 17:20:53 +01:00
Riley Thompson
edb5eaad63 Handle non-dates in sqlite date columns (#71492)
* fix sqlite non date handling

* kondo
2026-03-26 12:14:00 -04:00
Nathan Voxland
ad9b980fef Merge remote-tracking branch 'origin/master' into persistent-queue 2026-03-26 11:12:10 -05:00
Nathan Voxland
96a308a64e CI fixes 2026-03-26 11:11:47 -05:00
Chris Truter
77afdaafc0 MCP further nits (#71478) 2026-03-26 16:08:18 +00:00
metamben
56f04b92ca Render |> as a single operator when formatting SQL (#71435)
Closes #70447
2026-03-26 16:06:37 +00:00
Braden Shepherdson
8020b65546 [MBQL lib] Add user docs for joins to lib.core (#71442)
Part of QUE2-366.
2026-03-26 16:06:19 +00:00
Sébastien
0cc35ac876 Sprinkled upsell gems in embed wizard (#71076) 2026-03-26 16:59:33 +01:00
Kevin Kelleher
617ca0f5f0 Fix boolean cartesian charts defaulting to timeseries axis (#71486) 2026-03-26 11:13:37 -04:00
John Swanson
607fb9ba58 Hide destination DBs from permissions (#71395)
* FE: do not show destination DBs in permissions editor

If you add a destination database, don't show it in the perms editor.

This was a temporary bug (disappears on refresh) BUT if you edit permissions
for the destination database then that is persisted, which is not great. I
will fix that in a separate PR.

* Don't add data permissions rows for destination DBs

- Exclude destination databases from the permissions graph

- Don't add permissions for destination DBs when creating a new group
2026-03-26 06:46:59 -08:00
Nathan Voxland
3c24edbf47 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	src/metabase/settings/models/setting.clj
2026-03-26 09:33:55 -05:00
Ngoc Khuat
74c8811981 Fix silent data loss when importing unparseable YAML files (#71421)
* Surface ingestion errors instead of silently skipping unparseable YAML files

The serdes ingestion layer was silently dropping YAML files that failed
to parse (introduced in #41887 as defensive coding for editor temp
files). This caused remote sync imports to silently lose entities when
YAML files were malformed or exceeded SnakeYAML's nesting depth limit,
with no error reported to the user.

Add `ingestion-errors` to the Ingestable protocol so the ingestion
layer collects parse failures and surfaces them through `load-metabase\!`.
When `continue-on-error` is false (default, used by remote sync), the
import fails immediately on ingestion errors. When true, errors are
collected and reported alongside load-phase errors.

The dotfile filter from #41567 is preserved — editor temp files are
still silently skipped before parsing is attempted.

Fixes #71257

* Rename ingestion-errors to ingest-errors, extract populate-cache\! helper, add e2e tests

- Rename protocol method to ingest-errors for consistency with ingest-list/ingest-one
- Extract populate-cache\! helper to DRY up duplicated cache-population logic
- Add e2e test for continue-on-error true/false with ingestion errors

* Add tests for ingest-errors on IngestableSnapshot and wrapper delegation

* Fix log/warnf misuse, tighten tests, remove stale comment

- log/warnf -> log/warn to prevent MissingFormatArgumentException
  when error messages contain % characters
- Add tests for ingest-errors ordering contract and multi-file corruption
- Tighten continue-on-error assertion to check exact error count
- Remove stale comment describing pre-fix behavior

* Include file names in ingestion error messages

Wrap parse/read exceptions with ex-info containing the file path,
so the error message shows which files failed, e.g.
"Failed to read 1 file(s) during ingestion: bad_card.yaml"
2026-03-26 23:29:58 +09:00
Oleksandr Solovyov
ce15b2d9f0 fix metabot sql tools incorrectly checked query type (#71428) 2026-03-26 14:06:13 +00:00
github-automation-metabase
e5db491df4 Auto-update documentation for master (#71454)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-26 09:54:44 -04:00
Chris Truter
fdffe7dc82 Add db fallback for renamed settings (#71470) 2026-03-26 15:42:32 +02:00
lbrdnk
3bd3bf5b6a Edit chart fix (#71424)
* Add edit_chart.md instructions

* Ensure ids of state elements are stringified

* Cleanup

* Test

* add test and do cleanup

* Review comments
2026-03-26 14:00:04 +01:00
Chris Truter
c940bb3935 Add FKs from transforms back to tables (#70617) 2026-03-26 13:40:22 +02:00
Timofey Kachalov
366c74c02e Support entityId for guest embedded questions (#71246) 2026-03-26 14:44:00 +04:00
Chris Truter
0303419907 Increase transform test timeout (#71453) 2026-03-26 12:26:05 +02:00
Sébastien
1511899a7e Implement proper column width measurement for custom font sizes (#71407) 2026-03-26 11:08:04 +01:00
lbrdnk
b1a2673e1a Inject context in user message (#71045)
* Add context injection to user message

* Remove context from internal template

* whitespace

* Adjust tests

* Apply suggestion from @appleby

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>

* use lib

---------

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
2026-03-26 10:42:20 +01:00
Nicolò Pretto
7074e0236a fix frontmatter in add-tracing skill (#71438) 2026-03-26 09:38:16 +01:00
Nemanja Glumac
ddba65c368 Add E2E (questions) tests on top of the cross-version automation (#70190) 2026-03-26 09:13:57 +01:00
Nathan Voxland
93b375bbe2 Merged from master 2026-03-26 01:33:25 -05:00
Edward Paget
d8bb291939 Inline malli refs and flatten root anyOf in MCP tool schemas (#71457)
* Inline malli refs and flatten root anyOf in MCP tool schemas

MCP clients (Claude API, OpenAI, Gemini, AWS Bedrock) reject or
mishandle $ref and top-level anyOf in tool input schemas. Fix by:

- Walking malli schemas with ::walk-refs and ::walk-schema-refs to
  replace all registered-schema refs with their dereferenced content
  before JSON Schema generation, so mjs/transform never emits $ref
- Flattening root-level anyOf into a merged object schema for
  construct_query (table vs metric request union)
- Expanding construct_query tool description to explain table vs
  metric query differences since the schema no longer structurally
  separates them

Removes all $ref/$defs sanitization code and the defs accumulator
atom that are no longer needed.

* Replace :or/:and with :merge at malli level to eliminate anyOf/allOf

Instead of post-processing JSON Schema to flatten anyOf/allOf, handle
it at the malli schema level: in inline-malli-refs, replace :and with
:merge (eliminates allOf from the encode-map pattern) and :or with
:merge after making all entries optional via mut/optional-keys
(eliminates anyOf, all properties become optional in the merged
output).

This produces clean flat {type: "object", properties: {...}} schemas
that all MCP clients can handle. The construct_query tool now has all
table and metric properties in a single flat schema with none
required, and the description explains which to use.

Removes flatten-any-of and clojure.set dependency.
2026-03-26 06:21:33 +00:00
Nathan Voxland
ca3a2ea136 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	src/metabase/search/core.clj
#	src/metabase/search/ingestion.clj
#	src/metabase/search/task/search_index.clj
#	src/metabase/testing_api/api.clj
2026-03-25 23:49:31 -05:00
Aleksandr Lesnenko
1132bfd402 New Metric Home page (#71055) 2026-03-26 03:05:51 +00:00
Nathan Voxland
e9f6c93013 Improved performance benchmark and added back skip lock 2026-03-25 21:17:35 -05:00
Maksym Yakubych
37f3a01838 [Metabot] Bring your own keys (#70714)
* move ee/llm into oss

* lots of file movement

* move slack connect to opensource

* ability to have enterprise-only tools

* move tests

* Fix stale metabot-v3 aliases, dangling module refs, disabled linting, broken test paths, and typo

* start using deprecated-name, more ns path fixes

* move llm transforms code to oss

* fix namespaces

* whitespace fix

* checkpoint: switch tools to use mu/defn or defenterprise directly

* compilation fix

* lint fixes

* move around some code to break drivers dependency

* fix tests

* fix tool calls

* sort routes

* fix openapi

* fix module config

* lint

* fix clj-kondo

* fix test

* fix token check tests

* cljfmt

* fix slack test

* maybe fix dashboard tests?

* cljfmt

* is this a fix for dashboard tests

* move metabot models to oss

* untangle module config after rebase

* fix module order

* cleanup

* add back ai service-related settings that are still used

* move some more code to more appropriate places

* more code movement

* better schema names

* clean up mu/defn function name formatting

* update module config

* remove unneeded ai service-related test

* fix module config again

* fix auth in tests by removing more ai service stuff

* enable native agent by default

* test transforms over normal function calls

* requires

* pass through metabot-id to tool calls instead of hardcoding embedded-metabot-id, to fix answer sources test

* fix wrap-tools-with-state calls

* try to fix failing field/dashboard tests by matching the code on master (might have been from a bad rebase)

* Revert "try to fix failing field/dashboard tests by matching the code on master (might have been from a bad rebase)"

This reverts commit cd5ec8b487.

* hard revert parameters.dashboard-test to the version on master after the latest rebase

* mark snippet tests as sequential to try to fix perms test issues, remove a couple stray metabot feature checks

* move entity analysis + sql fixing code to oss

* wrap dashboard tests with with-full-data-perms-for-all-users to isolate the failure

* move ai-entity-analysis and ai-sql-fixer under the metabot module

* fix module test

* remove now-unneeded ai feature falgs

* disable perms cache for these failing dashboard tests

* feat: self-hosted metabot provider settings

* test: patch is-hosted temporarily

* fix: grouping

* move files to the frontend/ folder

* move MetabotProviderSection into MetabotSetup to accomidate design changes

* make anthropic the only allowed provider, updat sonnet 4.6 as default model, small layout change to api key input

* remove PLUGIN_METABOT usage, remove purchase pages, consolidate new connections settings ui

* remove oss impl of sql gen on the FE

* remove MetabotSettingUpModal, add alert for slackbot requiring metabot be setup, remove PLUGIN_METABOT, PLUGIN_METABOT.isCloudManaged checks now check llm-metabot-configured? which breaks things for enterprise for now

* add mock Metabase provider

* fix build

* impl copy feedback

* type-fix

* clean up

* fix unit tests

* fix metabot e2e tests

* type fix

* more test fixes

* fix semantic search tests

* more test fix

* kondo fix

* more test fixes

* copy change

* more kondo fixes

* app db test failure fixes

* fix failing BE tests

* fix e2e tests

* more e2e failure fixes

* fix typo

* remove mocked out endpoint definition

* fix last failing e2e test

---------

Co-authored-by: Oleksandr Solovyov <o@solovyov.net>
Co-authored-by: Noah Moss <noahbmoss@gmail.com>
Co-authored-by: Sloan Sparger <sloansparger@gmail.com>
2026-03-25 23:49:07 +00:00
Chris Truter
87dc660191 Minor improvements to MCP server (#71406)
* Fix token scope logic to match middleware

* Add :secure to CSRF and DRY up

* Add comment to magic number for clarity

* Clean up complex threading

* Don't clobber token-scopes

* Optimize and improve no user-id failure mode

* trim comment fluff

* Simplify and avoid double str call

* Use database time for revoke-token for robustness

* Use long for user-id actually

* Enable refresh token rotation

A stolen refresh token was reusable for its entire 30-day TTL with no
way to detect theft. The oidc-provider library supports rotation — on
each refresh grant the old token is revoked and a new one issued.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Sanitize brand-color on consent page to prevent CSS injection

The brand-color setting is interpolated via h/raw into a <style> block on
the consent page. A non-hex value could break out of the CSS rule.
Validate defensively at the rendering site rather than changing the setting
setter, to handle already-persisted invalid values gracefully.

* HMAC-bind consent params to CSRF token and sanitize error messages

Two security improvements to the OAuth server:

1. The authorization decision endpoint re-parsed OAuth parameters from
   the POST body without verifying they matched what the user saw on
   the consent page. A modified form could request broader scopes than
   shown. Now the authorize endpoint HMAC-signs the parsed params using
   the CSRF token as key, and the decision endpoint verifies the
   signature against the re-parsed params before proceeding.

2. Error catch blocks on /authorize, /authorize/decision, and /token
   returned raw exception messages that could leak internal details
   (client IDs, redirect URIs, expected vs actual values). Now returns
   generic RFC-compliant error descriptions and logs details server-side.

* Truncate long client name. Show client id

* Non-functional nits

* Clean up

* Align and extract helper

* DRY OCD

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:04:40 -04:00
Chris Truter
40691f70d8 Faster search index sync when loading snapshots (#71410) 2026-03-25 21:42:40 +00:00
Noah Moss
f4b0e5946b Consolidate metabot-enabled checks and add them to a number of endpoints (#71366)
* consolidate metabot-enabled checks and add them to a number of endpoints

* switch describe_tests to use mbql-query helper for cards

* Remove metabot.settings namespace import
2026-03-25 21:17:14 +00:00
Noah Moss
f3a2cfab7f Query pagination for MCP (#70971)
* Combined /v1/query endpoint with pagination and continuation tokens

- Add /v1/query that combines query construction and execution in one step
- Implement continuation_token-based pagination for large result sets
- Cap agent query rows at 200 per page; pagination stops at userland limits (2k/10k)
- Refactor construct-query into shared construct-query* helper
- Move agent-api dispatch behind defenterprise seam in EE MCP tools
- Add streaming JSON-RPC support for tool results in MCP layer
- Add json-string-escaping OutputStream for embedding streamed JSON in JSON-RPC
- Move /agent route out of naughty-routes into intentional top-level-routes
- Fix SSO test_setup to handle nil server port in CLI test runner

* Remove streaming JSON-RPC, buffer all tool responses in memory

Strip the streaming code path from the MCP layer so this branch
focuses purely on the query tool and pagination. Buffering ~120KB
for 200 rows is fine for the limits we enforce.

- Remove json-string-escaping OutputStream and streaming-tool-response
- Revert MCP api.clj to synchronous Ring form (no SSE streaming)
- Move StreamingResponse materialization into EE MCP tools layer
- Simplify invoke-agent-api to handle only plain map responses
- Remove streaming-specific tests (escaping, SSE streaming, error)

* a bunch of other changes to try get the rebased build working

* Roll back a bunch of fixes from the oss branch that don't need to be fixed here

* restore code accidentally lost via multiple rebases

* update modules + lint

* strip out dead ee code

* update tool  count test
2026-03-25 16:47:10 -04:00
Nathan Voxland
817eb1d787 Roll back transform perms (#71094) 2026-03-25 15:27:25 -05:00
Nathan Voxland
89786605c1 Fixing tests and created a mq-perf script 2026-03-25 15:19:29 -05:00
Egor Grushin
8b5224136b Cypress bail (#71420)
* add bail feature to the e2e stress test flake workflow

* add bail feature to the e2e stress test flake workflow

* add bail feature to the e2e stress test flake workflow

* Update e2e/support/cypress.js

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>

* renamed BAIL to FAIL_FAST, replace Cypress.env with Cypress.expose

---------

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2026-03-25 20:11:22 +00:00
Braden Shepherdson
051c1a6b25 [Params] Always return [] for param /values requests (#71302)
Fixes #71164.

On the BE, always return an empty list rather than nil. Old models with `:id` different from `:field_ref` in their metadata could result in `{:values nil ...}` being returned, which breaks the schema and FE. See #71164 for full details.
2026-03-25 20:11:07 +00:00
Jeff Bruemmer
c3c7feeddf docs - OIDC (#70892) 2026-03-25 13:54:47 -04:00
appleby
274b7de269 Remove dangling reference to use-native-agent setting in e2e tests (#71437)
This defsettings was removed in 311b735ae5
2026-03-25 16:48:29 +00:00
Stas Gavrylov
a0bea40dab GDGT-1755: Migrate common components from deprecated Popover to Mantine Popover (#70503)
* GDGT-1755: Migrate RightClickPopover to use Mantine

* GDGT-1755: Migrate DropdownSidebarFilter to Mantine Popover

* GDGT-1755: Migrate ParameterTargetWidget to Mantine Popover

* GDGT-1755: Make DropdownSidebarFilter close on Esc press

* GDGT-1755: Migrate GroupSelect to Mantine Popover

* GDGT-1755: Migrate deprecated Select to Mantine popover to remove deprecated Popover

* GDGT-1755: Cleanup. Delete unused deprecated components

* Fix prettier

* fix: fix test failures after Popover cleanup

- Remove jest.unmock for deleted Popover module in ChartSkeleton tests
- Add missing data-testid="popover" to DropdownSidebarFilter dropdown

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Cleanup

* GDGT-1755: Address code review comments

* Clean up Popover.module.css: keep only tippy.js global styles

Remove unused module-level classes and obsolete tether-related classes.
Import the remaining global styles in TippyPopover.tsx.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-25 18:33:12 +02:00
Nicolò Pretto
2576505465 fix flaky test in embedding hub (#71434) 2026-03-25 17:04:32 +01:00
Nick Fitzpatrick
9f5298fa9a Update TablePicker when users publish/unpublish tables, change name (#70954)
* update TablePicker when users publish/unpublish tables, change name

* refetch tables in useTableLoader

* update table owners
2026-03-25 21:27:23 +05:30
Kevin Kelleher
07f25c0cc7 Allow changing conditional formatting to color range when rule condition is set (#71079) 2026-03-25 10:59:01 -04:00
Nicolò Pretto
cfb3ab406c Implement SSO setup checklist locking for steps 2 and 3 until JWT is configured (#71345)
* Implement SSO setup checklist locking for steps 2 and 3 until JWT is configured

* remove e2e for something already covered by unit

* update checklist default values after merging master
2026-03-25 15:52:01 +01:00
Egor Grushin
a4db64b01b GDGT-2017 write watermark to the DB before setting "succeed" status t… (#71334) 2026-03-25 14:21:55 +00:00
Noah Moss
efcefcad96 Avoid sending only whitespace in a slack API request (#71391)
Don't send only whitespace to the Slack API
2026-03-25 14:09:29 +00:00
Braden Shepherdson
38b071e39d [MBQL lib] Add user docs for filter functions in lib.core (#71035)
Part of QUE2-366.
2026-03-25 14:04:28 +00:00
Braden Shepherdson
46902911c8 [QP] Change the nested query alias from source to __mb_source (#70955)
closes #70224
Fixes QUE2-396.

### Description

This is necessary because `source` is a reasonably common name for a
column, and databases diverge on how they treat a reference like
`"source"."source"`:

- Postgres et al see the relation `source` in scope, and access its
  column called `source`, and all is well.
- Athena et al:
  - See that there is a **column** `source` in scope that doesn't require a prefix.
  - Assume it's a nested column with `ROW` type, and try to access the
    nested `source` field.
  - Type mismatch! It's a string or whatever, not `ROW`.

This PR doesn't *eliminate* the problem, but there's not really anything
we can do to fix Athena's honestly pretty odd choice of how to resolve this
ambiguous parse tree. But by changing our hard-coded alias for all
nested queries from `source` to `__mb_source`, we can make it extremely
unlikely that it will collide with a column that's in scope.
2026-03-25 13:53:00 +00:00
Noah Moss
23f686e698 Include conversation history in slackbot feedback (#71359) 2026-03-25 09:47:42 -04:00
Oleksandr Solovyov
311b735ae5 clean up references to ai-service (#71353) 2026-03-25 15:33:26 +02:00
Ngoc Khuat
e2f1a1a315 Fix flaky schema-change integration test (follow-up to #70863) (#71339) 2026-03-25 21:51:33 +09:00
Alex Yarosh
1f7e4b12f7 docs: update embedding skills (#71415)
Remove development note from SSO for embeds section
2026-03-25 08:30:39 -04:00
Sébastien
178ecbaeef fixed flaky (#71405) 2026-03-25 13:22:25 +01:00
Nick Fitzpatrick
5ac346612f Small positioning adjustments to the data studio nav bar (#71379)
* Small positioning adjustments to the data studio nav bar

* pr feedback
2026-03-25 17:36:41 +05:30
Chris Truter
2ace0b69c1 Built-in MCP server (#70787)
* Add MCP server with agent API integration

Implements an MCP (Model Context Protocol) server for Metabase that exposes
agent API endpoints as MCP tools. Includes an Oauth server, SSE transport, 
session management, scope-based auth, and tool dispatch via defendpoint metadata.

Co-Authored-By: Edward Paget <edpaget@users.noreply.github.com>
Co-Authored-By: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2026-03-25 05:04:46 -04:00
Nick Fitzpatrick
6b8d7846de Update response on set token with network error (#70959)
* Update response on set token with network error

* report error message from checker when setting token

Currently when anything goes wrong during token checking while we're
setting a token, we *always* report that the token is invalid. This is
incorrect.

The token checker already gives us a descriptive `status` for the token,
which can tell the user whether the token is invalid or if we just
weren't able to check it.

One slight change here is to add `:canonical? true` to responses we
receive from MetaStore directly. This allows us to respond with the
correct HTTP status, since if we receive a response from the MetaStore
that tells us the token is invalid, that's a 400 error, where if we
weren't able to get a canonical response at all, that's a 503.

* add unit test

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-03-25 14:19:32 +05:30
Nathan Voxland
82f5dea54d Code cleanup 2026-03-25 02:28:42 -05:00
Chris Truter
d34d1dc9ff Fix search related testing race conditions (#71290)
Closes [BOT-1105: Search API tests fail with missing temp table](https://linear.app/metabase/issue/BOT-1105/search-api-tests-fail-with-missing-temp-table)
2026-03-25 09:10:23 +02:00
appleby
95f85256c2 BOT-1172 Fix markdown link buffering for slack links (#71388)
Fix markdown link buffering for slack links

find-potential-slack-link-start was looking for a full `<metabase://` prefix which doesn't work if the link prefix is
split across streamed text chunks. Updated it to deal with this case.
2026-03-25 00:37:50 +00:00
appleby
33661d4b6a BOT-1044 Convert links back to metabase:// format before sending to llm (#71125)
* BOT-1044 Convert links back to metabase:// format before sending to llm

This is a re-implementation of https://github.com/metabase/ai-service/pull/597

resolve-links converts metabase:// links into real URLs before sending them back to the client. When the LLM sees
these resolved URLs in the conversation history, it can get confused and start generating resolved links
itself (e.g. /question#<base64>), rather than following instructions to always use metabase:// links. This sometimes
results in wrong/hallucinated base64 repr, especially in longer conversations where many resolved links accumulate in
the history.

With this commit, we add a link-registry to the agent state to record every link rewritten by resolve-links, and use
invert-links to restore them to metabase:// URIs in the message history before sending it to the LLM for completion.

* Simplify state management for link-registry-atom

We don't need to track it separately in the agent state in init-agent. Just extract it from the agent memory in
the loop-step and sync it back after the llm call.

* Only invert urls in markdown links

* Replace handcrafted legacy MBQL in markdown_link_buffer_test.clj

* Mark deftests ^:parallel in markdown_link_buffer_test.clj

* Mark deftests ^:parallel in links_test.clj and breakup into smaller deftests

* Replace handcrafted legacy MBQL in links_test.clj

* Move resolve-slack-links into metabot.agent.links ns

To match existing resolve-links handling for generic metabase links

* Use with-temporary-setting-values to override site-url in markdown_link_buffer_test.clj

To match existing conventions in the codebase.

* Consolidate with-temporary-setting-values and breakup deftests in markdown_link_buffer_test.clj

* Record slack links into the registry map and invert them before sending history back to the llm

See f90619f5e2

* Fix agent memory initialize-test

* review feedback: extract part->invert-links-key helper
2026-03-24 23:41:03 +00:00
github-automation-metabase
d39d8c5800 Auto-update documentation for master (#71389)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-24 18:06:41 -04:00
Ryan Laurie
60da7517d1 Allow toggling auto releases via variable (#71313)
allow toggling auto releases via variable
2026-03-24 15:58:32 -06:00
appleby
ea43a75160 Fix metabot snowplow test flakes (#71337)
Fix snowplow test flakes

In call-llm-snowplow-test and call-llm-structured-snowplow-test filter the snowplow events to remove potential
new_instance_created events.
2026-03-24 17:23:04 -04:00
Noah Moss
77f28324a0 Add saved question display type to metabot context (#71372)
add saved question display type to metabot context
2026-03-24 20:14:19 +00:00
metamben
778dcf54a1 Introduce config option to specify known hosts for SSH tunnels (#71194)
* Introduce config option to specify known hosts for SSH tunnels

Closes QUE2-424
2026-03-24 22:44:56 +03:00
Alex Yarosh
161ebe81d5 docs: tenant example (#71365)
* Refine tenant attributes and permissions documentation

* Update docs/embedding/tenants.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/tenants.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-03-24 15:38:54 -04:00
Jeff Bruemmer
1dbfa65885 docs - agent API oss (#71380)
* oss and session

* link

* update
2026-03-24 14:51:59 -04:00
Cam Saul
8cb8e93394 Update GH teams config + modules config for Querying Platform (#71182) 2026-03-24 18:25:45 +00:00
Cam Saul
afc8eb428e Fix Snowflake Netty code scanning alert (#71309)
* Fix Snowflake Netty code scanning alert

* Dummy commit to trigger CI
2026-03-24 18:18:05 +00:00
Anderson
1fbe726c08 Fix ARIA grid role hierarchy in DataGrid for accessibility compliance (#70978)
* Fix aria-expanded on dashboard filter trigger button (#70543)

Closes https://github.com/metabase/metabase/issues/70543

### Description

Move aria-expanded from a wrapper div to the actual trigger button element
for dashboard filter popovers. Mantine's Popover.Target injects
aria-expanded via cloneElement onto its direct child. Previously, a Box
wrapper div was the direct child, so aria-expanded landed on a
non-interactive div instead of the button. This restructures the
component hierarchy so ParameterValueWidgetTrigger (which renders as a
button) is the direct child of Popover.Target, and moves the Sortable
wrapper outside the Popover.

### How to verify

1. Open a dashboard with filter parameters
2. Inspect the filter trigger button element in the DOM
3. Verify aria-expanded is on the button element (not a wrapper div)
4. Click the filter to open the popover and confirm aria-expanded
   toggles to true on the button

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

* Fix ARIA grid role hierarchy in DataGrid for accessibility compliance (#70547)

Closes https://github.com/metabase/metabase/issues/70547

### Description

The DataGrid component had an invalid ARIA role hierarchy: `role="button"`
elements (from dnd-kit's useSortable) were nested directly inside a
`role="grid"` element without proper intermediate roles. Per the WAI-ARIA
grid pattern, the hierarchy must be: grid > rowgroup? > row > gridcell/columnheader.

This commit:
- Adds `role="rowgroup"` to header and body container divs
- Adds `role="row"` to the header row div
- Adds `role="columnheader"` to header cell wrapper divs in DataGrid
- Adds `role="gridcell"` to body cell wrapper divs in DataGrid
- Strips the invalid `role="button"` that dnd-kit injects into SortableHeader
- Removes now-redundant role attributes from HeaderCellWrapper and BodyCell
  (roles are now correctly placed on their parent wrapper elements)

### How to verify

1. Open any dashboard with a table/grid visualization
2. Inspect the DOM of the table-scroll-container element
3. Verify the ARIA role hierarchy follows: grid > rowgroup > row > columnheader/gridcell
4. Run an accessibility audit tool and confirm no `role="button"` violations inside the grid

* Keep button role in sortable header (it's ok since it's not wrapping the columnheader)

* Clean up

* Add unit test

* Fix a few tests

* Fix more e2e tests broken by ARIA role changes

* Fix more e2e tests

* Fix embedding-native.cy

* Another e2e test fix batch

* Fix e2e tests (again)

* fix reproductions-3.cy.spec.js
2026-03-24 15:05:33 -03:00
Jeff Bruemmer
2aec3aa887 Update agent API reference documentation (#71360)
* Update agent API reference documentation

Removed requirement for Metabase Pro/Enterprise from documentation.

* path
2026-03-24 17:36:43 +00:00
Nicolò Pretto
446de63944 feat(embedding-hub): add "copy dashboard to shared tenant collection" step (#70726)
* wip

* wip3

* test ci

* update tests

* remove code from tests

* sort xray dashboards

* cleanup

* clean up tests

* small refactor

* more cleaning up

* keep step disabled if  tenants is not active
2026-03-24 16:18:41 +01:00
Oleksandr Solovyov
08717ff883 closing-connection-native-agent-test: lower amount of chunks we check for (#71354) 2026-03-24 16:38:06 +02:00
Chris Truter
ccef0576f9 Calculate init time reliably (#71356) 2026-03-24 14:16:25 +00:00
github-automation-metabase
1b12502ec3 Revive and merge PR #67694: disable sync_schema side-effect in db-operations-test (#71201)
Fix H2 lock timeout in db-operations-test by mocking sync task

Split the monolithic db-operations-test into three focused tests:
- non-admin-sync-schema-test: mocks quick-task/submit-task! to prevent
  the actual sync job from running, eliminating the race condition with
  DATA_PERMISSIONS cleanup in mt/with-all-users-data-perms-graph!
- non-admin-discard-field-values-test: isolated test for discard_values
- non-admin-rescan-field-values-test: isolated test for rescan_values

Also renames update-database-test, delete-database-test, and fetch-db-test
to non-admin-* for consistency, and adds explicit permission-denial (403)
test cases to each test.

Revives the fix from closed PR #67694.
2026-03-24 14:00:45 +00:00
Braden Shepherdson
b42c2f6605 [QP] Override LIMIT for pivot queries to ensure consistent results (#71033)
Closes #70963
Fixes QUE2-431.

Previously, pivot queries got the same default row limits added as any
aggregated query. But since pivot queries synthesize the results from
several inner queries with different subsets of breakouts, they
have different row counts.

The main ("row details") query the user wrote has all the breakouts,
so it has the most rows. If that query gets truncated, only a subset
of the data is returned, leaving gaps in the pivot table. Worse, the
sub-queries with other subsets of the breakouts, intended to collect
group, column and row subtotals, and the grand total, are inconsistent
with the details in the cells, and with each other, because they can
all end up `SUM`ing (etc.) over different sets of the raw rows.

With this change, a new and much larger row limit is permitted for the
pivot sub-queries. The pivot table viz contains one cell for each
aggregation in the query, multiplied by the rows of the main query.
We budget for **200k cells**, divide by the number of aggregations,
and that becomes the row limit.

If the row details query reaches that limit, the query is rejected:
- Other sub-queries are skipped
- A `pivot-rows-truncated` flag in the results signal the FE
- Which shows an error suggesting the user add a filter or remove
  breakouts to lower the row count.

Some reasonable pivot queries might still be excluded, but now we never
run a pivot query with incorrect data in it. If we execute the query and
render the pivot results, then all the returned data should be correct.
2026-03-24 13:45:34 +00:00
Nick Fitzpatrick
cfa96f3fe0 Catch drag events on Dashcard placeholders (#71274)
* Catch drag events on Dashcard placeholders

* scope drag events, add test
2026-03-24 18:46:31 +05:30
github-automation-metabase
3f55d1b9f4 Use env var indirection in Loki stress-test workflow (#71349)
Fix script injection via env var indirection in loki-stress-test-flake-fix.yml
2026-03-24 13:48:02 +01:00
Nemanja Glumac
acbf9bcc88 Delete Claude bug fix workflow (#70993) 2026-03-24 12:52:30 +01:00
Uladzimir Havenchyk
442cf4abb9 fix: cross branch migration workflow (#71153) 2026-03-24 14:31:51 +03:00
Kamil Mielnik
aee64c6047 GDGT-1869 Remove "as VisualizationSettingsDefinitions" casts (#71217) 2026-03-24 17:30:47 +07:00
Nicolò Pretto
41ca038f67 feat(embedding hub): add ability to hide sidebar for some pages (#71278) 2026-03-24 10:09:27 +01:00
Chris Truter
a0896d1faf Fix clickhouse test flake (#71306) 2026-03-24 10:26:47 +02:00
Nathan Voxland
ad62aed71a Cleaning up code 2026-03-24 02:15:25 -05:00
Nathan Voxland
3ab76adf8d Merged from master 2026-03-24 01:36:35 -05:00
Nathan Voxland
1f019c1e10 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	enterprise/backend/src/metabase_enterprise/action_v2/data_editing.clj
#	enterprise/backend/test/metabase_enterprise/action_v2/api_test.clj
#	enterprise/backend/test/metabase_enterprise/agent_api/api_test.clj
#	enterprise/backend/test/metabase_enterprise/serialization/v2/e2e_test.clj
#	enterprise/backend/test/metabase_enterprise/serialization/v2/load_test.clj
#	src/metabase/analytics/prometheus.clj
2026-03-24 01:28:52 -05:00
Nathan Voxland
3e4335a798 Merge remote-tracking branch 'origin/persistent-queue' into persistent-queue 2026-03-24 01:19:44 -05:00
Nathan Voxland
70967125aa Code cleanup 2026-03-24 01:16:36 -05:00
Nathan Voxland
5921542894 Code cleanup 2026-03-24 01:05:12 -05:00
Romeo Van Snick
c8cb9c2f04 Remove sync buttons for managed cloud databases (#71203)
* Remove sync buttons for managed cloud databases

* Remove sync settings button for table in attached data warehouse in admin > table metadata and data studio
2026-03-24 14:17:29 +11:00
Fraser
b8c90cdfbe Push shared files down from feature modules (#71137) 2026-03-24 15:24:34 +13:00
Romeo Van Snick
0ab5a0f603 Fix parameter tags reordering in the presence of snippet tags (#71209)
* Disregard snippet tags when reordering parameters

* Add repro for metabase#69160

* Wording

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>

---------

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
2026-03-24 11:59:52 +11:00
Riley Thompson
8f9282dca1 Don't generate join alias that matches source table name (#70876)
* include source name in taken names

* add test

* Update src/metabase/lib/join.cljc

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>

* fix tests

* fix test

* Fix test metadata for self-join test

* e2e test fix attempt

* second attempt

---------

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2026-03-24 00:39:09 +00:00
Nathan Voxland
8c572f77f4 Fix race conditions in submit-delivery! and topic offset advancement
- submit-delivery!: atomic busy-check and registration via single swap!
  to prevent concurrent handlers for the same channel
- start-worker-pool!: use compare-and-set! to prevent pool leak on
  concurrent initialization
- Topic backends: only advance offset when submit-delivery! returns true,
  preventing silent message loss when channel is busy
2026-03-23 19:10:23 -05:00
bryan
c8560d8251 Models to transforms (#70735)
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-03-23 23:59:16 +00:00
Nathan Voxland
7e5bb21c3d Fix high-priority issues: retry flush failures, non-blocking batch processing, atomic after-commit drain
- Publish buffer: re-buffer messages on flush failure instead of dropping them, with Prometheus counter
- Queue/topic processing: centralized non-blocking dispatch via shared worker pool in mq.impl, with busy-channel tracking so poll threads never block on listener execution
- Queue heartbeats: poll thread updates status_heartbeat every 2min for in-flight batches to prevent stale recovery during long processing
- After-commit callbacks: atomically drain with reset-vals! loop to support callbacks that register new callbacks
- Document all-or-nothing ACK semantics on queue bundle retry in handle! docstring
2026-03-23 18:58:14 -05:00
appleby
74a9d5baeb BOT-1157 Update metabot prometheus and snowplow metrics to include both provider and model (#71259)
We now report the full provider and model rather than just the model, e.g.

    anthropic/claude-haiku-4-5 -> openrouter/anthropic/claude-haiku-4-5
    claude-haiku-4-5           -> anthropic/claude-haiku-4-5

In addition to being useful info to capture, this matches the behavior of the pre-existing ai-service metrics.
2026-03-23 16:42:40 -07:00
bryan
fb428f307e Extend ci-report to accept branch names and commit SHAs (#70742) 2026-03-23 15:50:21 -06:00
Jeff Bruemmer
e50748827a docs - sdk playground (#71314)
* sdk playground link

* edit

* image

* Optimized 1 images, saved 188.7 KB (35.5% smaller)

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-03-23 21:48:31 +00:00
Ben Grabow
9ec99afb69 Ghy-3258/table tag dependencies missing in incremental transforms (#71316)
Include table tags as dependencies of native queries
2026-03-23 16:40:06 -05:00
Oleksandr Solovyov
c2ad36cccb move ee/llm into oss (#71068)
* move ee/llm into oss

* lots of file movement

* move slack connect to opensource

* ability to have enterprise-only tools

* move tests

* Fix stale metabot-v3 aliases, dangling module refs, disabled linting, broken test paths, and typo

* start using deprecated-name, more ns path fixes

* move llm transforms code to oss

* fix namespaces

* whitespace fix

* checkpoint: switch tools to use mu/defn or defenterprise directly

* compilation fix

* lint fixes

* move around some code to break drivers dependency

* fix tests

* fix tool calls

* sort routes

* fix openapi

* fix module config

* lint

* fix clj-kondo

* fix test

* fix token check tests

* cljfmt

* fix slack test

* maybe fix dashboard tests?

* cljfmt

* is this a fix for dashboard tests

* move metabot models to oss

* untangle module config after rebase

* fix module order

* cleanup

* add back ai service-related settings that are still used

* move some more code to more appropriate places

* more code movement

* better schema names

* clean up mu/defn function name formatting

* update module config

* remove unneeded ai service-related test

* fix module config again

* fix auth in tests by removing more ai service stuff

* enable native agent by default

* test transforms over normal function calls

* requires

* pass through metabot-id to tool calls instead of hardcoding embedded-metabot-id, to fix answer sources test

* fix wrap-tools-with-state calls

* try to fix failing field/dashboard tests by matching the code on master (might have been from a bad rebase)

* Revert "try to fix failing field/dashboard tests by matching the code on master (might have been from a bad rebase)"

This reverts commit cd5ec8b487.

* hard revert parameters.dashboard-test to the version on master after the latest rebase

* mark snippet tests as sequential to try to fix perms test issues, remove a couple stray metabot feature checks

* move entity analysis + sql fixing code to oss

* wrap dashboard tests with with-full-data-perms-for-all-users to isolate the failure

* move ai-entity-analysis and ai-sql-fixer under the metabot module

* fix module test

* remove now-unneeded ai feature falgs

* disable perms cache for these failing dashboard tests

* simplify test that was still using agent-api feature flag

* memoize spec-index-query by app db to fix failing search tests caused by new test execution order

* LLM OSS FE (#71197)

* bulk move files

* replace usage of /ee/metabot-v3/ to /metabot

* remove PLUGIN_METABOT

* fix broken metabot routes, removes metabot_v3 token feature usage

* remove PLUGIN_AI_*

* bring back enterprise vs oss behavoir, with the code still being OSS

* fix lint + unit tests

* fix embedding sdk stories

* add back missing FixSqlQueryButton.unit.spec.tsx test

* fix last references of `/ee/ai-*` endpoints

* pr feedback

* test fix

---------

Co-authored-by: Noah Moss <noahbmoss@gmail.com>
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2026-03-23 17:30:50 -04:00
Chris Truter
76b01b772b Define additional metrics for release monitoring (#71237) 2026-03-23 17:20:34 -04:00
Noah Moss
733176c925 Add cancelled check for sdk-tests (#71307) 2026-03-24 10:03:27 +13:00
Ryan Laurie
88a87db2b8 Sanitize database details during serialization import (#71311)
[59] Sanitize database details during serialization import (#335)

* Sanitize database details during serialization import

Strip low-level JDBC keys (classname, subprotocol, connection-uri, subname,
init) from database details during serialization import and reject h2 engine.

Also add subname and init to the connection-details dispatch blocklist and
sanitize details in h2 connection-details->spec as defense in depth.

* Use custom runners

* fix error printing and test

* rebind assert-not-h2! during tests

* kondo ignore

---------



# Conflicts:
#	.github/workflows/backend.yml
#	.github/workflows/cross-branch-migrations.yml
#	.github/workflows/tusk-sanity-check.yml

Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Co-authored-by: Nemanja <31325167+nemanjaglumac@users.noreply.github.com>
2026-03-23 14:40:06 -06:00
Ryan Laurie
45380db283 Send release jars to cloud bucket (#71093)
* update var

* do it in the tag step
2026-03-23 14:29:58 -06:00
metamben
84b79b9126 Reorganize QP module (#70808)
* Introduce qp.core and qp.test namespaces
2026-03-23 20:14:12 +00:00
Nathan Voxland
2c8c0e30aa Better consolidation of topic vs queue logic 2026-03-23 14:44:03 -05:00
Nicola Mometto
d6d3bbb89a Fix bug with temporal values in bigquery incremental transforms (#71291)
* fix: coerce temporal values used in incremental transforms filters

* fallthrough on LocalDateTime

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>

---------

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2026-03-23 18:41:40 +00:00
Alex Yarosh
1bb4b60d60 docs: workflow schedule (#71305)
docs workflow schedule
2026-03-23 14:33:38 -04:00
Sébastien
1827c0c37d Fixed dancing MB (#71211) 2026-03-23 16:48:56 +01:00
github-automation-metabase
5dd6f68c46 Fix title escaping for JSON (#71289) 2026-03-23 16:08:50 +01:00
Nemanja Glumac
c85d47365d Remove hard-coded Trivy version (#71287) 2026-03-23 15:03:46 +01:00
github-automation-metabase
17bca77f06 Auto-update documentation for master (#71268)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-23 09:19:13 -04:00
Jakub Chodorowicz
4c4c049ac8 update copy and styling of table variable select (#71101)
* update copy and styling of table variable select

* extract common LabelWithInfo component

standardize styling
2026-03-23 13:13:42 +01:00
Kevin Kelleher
38fa86db3f Fix scatter plot flicker on hover (#71036) 2026-03-23 07:38:27 -04:00
Nemanja Glumac
ac3a38209f Patch vulnerable Trivy action (#71282)
Resolves DEV-1712

Patches Trivy GitHub action to a version that is confirmed not to be affected by the supply chain attack. We're using SHA-1 instead of a tag for an improved security.

See: https://app.mendral.com/insights/01KM6NFNZPV1JS72KAPCA2K9XH
2026-03-23 12:22:55 +01:00
Chris Truter
c568186ebc Only run Eastwood (test) on master (#71232) 2026-03-23 12:30:13 +02:00
Nicolò Pretto
a49e97237f add ability to hide Our analytics in MiniPicker and hide it in the table picker in the embedding setup (#70920)
* add ability to hide Our analytics in MiniPicker

* remove changes not needed

* update getOurAnalytics with the values from EntityPicker
2026-03-23 11:12:55 +01:00
Fraser
f1c36719aa Move shared query_builder logic to querying (#71129) 2026-03-23 09:22:12 +00:00
Sébastien
292a667717 Fixes a loki flaky (#71225)
* loki flaky

* .

* .

* fonts
2026-03-23 10:02:28 +01:00
Kamil Mielnik
361549c5af GDGT-2024 Consolidate ChartSettingsWidget's noPadding, marginBottom, and borderBottom (#71154) 2026-03-23 14:25:07 +07:00
Romeo Van Snick
c009e25907 Fix timeline form icon input (#71199)
* Add icon to timeline icons

* Use Select from mantine/ui for timeline form

* Add test for icon in timeline creation
2026-03-23 16:21:20 +11:00
Romeo Van Snick
e13fd47144 Convert dataref to ts (#71062)
* Convert dataref to ts

* Fix unit test

* Fix actions

* Fix field reference

* Fix native data reference

* Fix field pane
2026-03-23 13:01:43 +11:00
metabase-bot[bot]
2812c4496d [chore] Update E2E test timings with recent data (#71265)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-03-23 10:11:46 +13:00
Nathan Voxland
28093ce803 Support Group Sync in OIDC (#71176) 2026-03-21 00:24:40 -05:00
Nathan Voxland
a649b08171 Field filter does not show dropdown values (#71114) 2026-03-21 00:23:58 -05:00
Egor Grushin
7a7585be68 Gdgt 1864 Add pinned columns and rows to the DataGrid (#70384) 2026-03-21 02:10:09 +00:00
Anderson
6b241a18fd Fix dashboard tab list items having role="button" instead of role="tab" (#70546) (#70976)
* Fix aria-expanded on dashboard filter trigger button (#70543)

Closes https://github.com/metabase/metabase/issues/70543

### Description

Move aria-expanded from a wrapper div to the actual trigger button element
for dashboard filter popovers. Mantine's Popover.Target injects
aria-expanded via cloneElement onto its direct child. Previously, a Box
wrapper div was the direct child, so aria-expanded landed on a
non-interactive div instead of the button. This restructures the
component hierarchy so ParameterValueWidgetTrigger (which renders as a
button) is the direct child of Popover.Target, and moves the Sortable
wrapper outside the Popover.

### How to verify

1. Open a dashboard with filter parameters
2. Inspect the filter trigger button element in the DOM
3. Verify aria-expanded is on the button element (not a wrapper div)
4. Click the filter to open the popover and confirm aria-expanded
   toggles to true on the button

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

* Fix dashboard tab list items having role="button" instead of role="tab"

Closes https://github.com/metabase/metabase/issues/70546

### Description

The Sortable wrapper around each dashboard tab item was applying a default
`role="button"` to its container div, which overrode the inner TabButton
`role="tab"` from the perspective of screen readers and accessibility tools.
Changed the Sortable wrapper to use `role="presentation"` so it is transparent
to the accessibility tree, allowing the inner TabButton role="tab" to be
properly recognized within the role="tablist" container.

### How to verify

1. Open a dashboard with multiple tabs
2. Inspect the tab items in the browser DevTools
3. Verify that tab items have `role="tab"` (not `role="button"`)
4. Verify the tab list container has `role="tablist"`

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

* Add issue number to test titles (#70546)

* Improve test

* Clean up
2026-03-20 20:19:30 -03:00
Ryan Laurie
b9573fc138 Use Local DigiCert for docker container builds (#71095)
use local cert

# Conflicts:
#	Dockerfile
#	bin/docker/Dockerfile
#	bin/docker/Dockerfile_ubuntu
2026-03-20 21:55:40 +00:00
Ben Grabow
8d41c7d068 Disallow adding new classpath resources as geojson paths (#70745)
* Disallow adding new classpath resources as geojson paths
2026-03-20 21:16:01 +00:00
Ben Grabow
e0365e3297 Revert "Temporarily disable app db version checks" (#71191)
Revert "Temporarily disable app db version checks (#70884)"

This reverts commit c5dcdc3238.
2026-03-20 15:36:19 -05:00
Braden Shepherdson
6b6ea19ab7 [MBQL lib] Add user docs for breakouts functions (#71034)
Part of QUE2-366.
2026-03-20 19:56:00 +00:00
Uladzimir Havenchyk
5a142f6eb1 add a workflow to publish custom viz npm package (#71221)
* add a workflow to publish custom viz npm package

* trigger CI
2026-03-20 12:32:56 -06:00
ignacio
cfacacd556 Update account settings docs (#71240)
This is currently doable in version 59.3.



See this issue: https://github.com/metabase/metabase/issues/63581
2026-03-20 15:22:12 -03:00
Uladzimir Havenchyk
a9b9ad9d85 chore: convert isa.js to typescript (#71014)
* chore: convert isa.js to typescript

* address comments

* address review

* revert back broken checks

* fix review
2026-03-20 20:35:23 +03:00
Chris Truter
68ec84ae4d Make all model imports and exports explicit (#71224) 2026-03-20 09:58:44 -07:00
Jakub Chodorowicz
6724b20a7b enable transform inspector only with advanced (python) transforms (#71067)
hide inspect tab when it's not supported by current features
2026-03-20 17:40:50 +01:00
Edward Paget
dd34d56120 fix: cancel serialization when client disconnects (#69864)
* fix: cancel serialization when client disconnects

Co-Authored-By: John Swanson <john.swanson@metabase.com>

* fix: complete serialization virtual thread streaming response

- Fix channel signal direction: use >!! to write to done-chan instead of <!! (read)
- Fix streaming response: use io/copy instead of .write for File objects
- Set explicit 200 status on success, set-status!/set-content-type! on error path
- Add Content-Disposition header on success for proper download behavior
- Clean up temp files on cancel and use finally for deterministic cleanup
- Remove commented-out old synchronous code
- Use canonical clojure.core.async alias (a instead of async)
- Add server module to enterprise/serialization allowed dependencies
- Relax full_stacktrace test threshold (200 -> 50 lines) to avoid JVM-dependent flakiness

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-03-20 11:28:41 -05:00
Braden Shepherdson
3559ec98b0 [QP] Do coercions (eg. Unix timestamps) with native sandboxing (RCLS) (#70885)
Fixes QUE2-376.

For MBQL queries, type coercions (like integers to Unix timestamps) only
get applied on the earliest stage where that field is introduced. When
the table the field comes from is sandboxed by a native query, an
extra stage is introduced but it doesn't do the coercion.

Decorates the metadata of any native sandbox column whose table counterpart had coercion defined.

It's unfortunately complicated inside lib since the metadata needs to be propagated through exactly one
stage boundary. If it propagates all the way then we get double-coercion and SQL errors.
2026-03-20 16:24:21 +00:00
Jeff Bruemmer
bc80f935a2 docs - transform inspector (#71188)
* draft

* edits

* edits

* toc

* Optimized 3 images, saved 326.0 KB (47.1% smaller)

* Update docs/data-studio/transforms/transform-inspector.md

Co-authored-by: Alex Yarosh <alexandra@metabase.com>

* edits

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-03-20 12:19:19 -04:00
github-automation-metabase
d0ac061fee Fix trivy action tag prefix (#71213)
fix: use v prefix on aquasecurity/trivy-action@v0.29.0 tag reference
2026-03-20 09:17:26 -06:00
Jeff Bruemmer
0cdcd2232c docs - agent resources for embedding (#71108) 2026-03-20 10:40:15 -04:00
Sébastien
8de615a69d Fixed empty csv for adhoc pivot tables in SDK (#71141) 2026-03-20 14:28:59 +01:00
Uladzimir Havenchyk
24968aa972 build: use a proper link for cert download (#71064) 2026-03-20 16:22:23 +03:00
Ngoc Khuat
a3ae3ba1f4 Transform inspector reorganization (#71136) 2026-03-20 10:34:24 +00:00
Nicola Mometto
22b6962656 default transforms impls with informative errors (#71145)
feat: provide default transforms impls with informative errors
2026-03-20 10:14:14 +00:00
Nicolò Pretto
94be4bfae3 Emb 1450 simplify sdk e2e test commands and docs (#71168)
* remove the embedding dev command and update the docs

* fix typo
2026-03-20 09:42:10 +01:00
Ngoc Khuat
39bc014f14 Server-side rendering for comment emails (#70938) 2026-03-20 07:55:16 +00:00
Fraser
4864f0ae24 Revert "Further pdf export improvements" (#71208)
Revert "Further pdf export improvements (#71031)"

This reverts commit 536d6bf22f.
2026-03-20 19:45:09 +13:00
Aleksandr Lesnenko
cd7eb82bdb remove emotion from browse pages (#71184) 2026-03-20 06:43:45 +05:30
Nick Fitzpatrick
536d6bf22f Further pdf export improvements (#71031)
* use cssText

* include font props on <text>, <tspan>, and <textPath> nodes
2026-03-20 05:59:35 +05:30
Anderson
ac092618ac Hide 'New metric' and 'Publish a table' actions on Data Studio Library empty state when in read-only mode (#71112)
* Fix: Hide metric creation and table publishing actions in read-only mode

In read-only instances (remote sync read-only mode), the Library still showed:
- 'New metric' action link in the Metrics empty state
- 'Publish a table' action button in the Data empty state
- 'New snippet' action link in the SQL snippets empty state

While the +New button was already hidden in read-only mode, the empty state
action links were not checking for this permission, allowing users to attempt
actions that should be disabled.

Changes:
- Add read-only mode check to EmptyStateAction component in LibrarySectionLayout
- Empty state actions now return null when in remote sync read-only mode
- Add e2e test to verify actions are hidden in read-only mode

* Refactor: use hideAction param and call-site guard instead of returning null from EmptyStateAction

Leverage the existing third param of createEmptyStateItem to suppress
actionUrl for metrics/snippets in read-only mode (consistent with how
the snippet tree handles it). Guard the 'Publish a table' button at
the EmptyStateAction call site in LibrarySectionContent, outside the
component itself. Reorganise the e2e test into the empty state describe
block.
2026-03-19 20:34:20 -03:00
Tyler Plude
03a09e1832 BOT-1127 Metabot Conditional Tool Schema Params (#71050)
* conditional tool schema input params

* simplify feature-available?

* unit tests

* applying to other search tools
2026-03-19 16:01:59 -07:00
Chris Truter
cc74f66a1b Restrict which models are accessible by each module (#71010) 2026-03-19 21:08:20 +00:00
John Swanson
bfa572ec6b Metric viewer can use metrics based on cards (#71107)
[UXW-3260: Metrics from models/table questions are not viewable in the Metrics viewer](https://linear.app/metabase/issue/UXW-3260/metrics-from-modelstable-questions-are-not-viewable-in-the-metrics)
2026-03-19 12:22:17 -08:00
Romeo Van Snick
fb38572a8c Fix flaky test in sidebar content (#71135)
Fix flaky test
2026-03-20 07:11:37 +11:00
lbrdnk
a02acabac1 Add database_engine to enhanced tables (#70968) 2026-03-19 20:59:15 +01:00
Rodrigo López Dato
198cd9a9a3 Remove X-Metabase-Session from autogenerated API docs in favor of X-API-Key (#71155)
* X-API-Key capitalization in docs

* Use X-API-Key instead of X-Metabase-Session in Scalar API docs
2026-03-19 19:32:45 +00:00
Eric Normand
c9c7f230fb Fix string field IDs leaking into bulk-metadata queries (#71167)
Add pos-int? guard to all-implicitly-joined-field-ids pattern match,
matching the guard already used by all-field-ids. String field names
(e.g. from native/model sources) were being collected and passed to
bulk-metadata, causing Postgres type mismatch errors.
2026-03-19 13:58:07 -05:00
Aleksandr Lesnenko
e1608e708d Add skill to migrate emotion to mantine and css modules (#71173)
add skill to migrate emotion to mantine and css modules
2026-03-19 14:21:59 -04:00
Chris Truter
213b1b5905 Add mechanism for more reliably renaming settings (#71088) 2026-03-19 14:12:31 -04:00
Eric Normand
42fdf326b6 Fix StackOverflowError in deduplicated column name resolution (#71096)
Add a dynamic guard `*in-deduplicated-column-resolution?*` and convert the
mutual recursion between `resolve-nonexistent-deduplicated-column-name` and
`resolve-from-previous-stage-or-source` into a loop. Previously, resolving
a field like `name_5000` would create O(N) deep mutual recursion, overflowing
the JVM stack at ~3000-4000 frames.
2026-03-19 12:24:47 -05:00
Anderson
3969de09bb Enable keyboard navigation in dashcard download data popover (#70541) (#70965)
* Enable keyboard navigation in dashcard download data popover

* Use mantine's Menu.Sub for submenus in DashCardMenu
2026-03-19 13:22:04 -03:00
bryan
99548507aa Add ci:run-<driver> and ci:run-all-drivers labels to mage driver decisions (#70894)
* Add ci:run-<driver> and ci:run-all-drivers labels to mage driver decisions

Allow force-running specific drivers or all drivers via PR labels,
overriding quarantine. Inserted at priority 3 (after H2/Postgres
always-run, before quarantine check). Added Labels of Interest and
All Drivers sections to help output.

* Add hint about ci:run labels in CI driver decisions output

Shows a helpful message in CI logs pointing users to the new labels
and the local help command for more info.

---------

Co-authored-by: Ben Grabow <ben.grabow@gmail.com>
2026-03-19 16:07:07 +00:00
Edward Paget
e0a2e2a80a fix: remove logging from session api (#70444) 2026-03-19 11:03:02 -05:00
Edward Paget
b8805a8d92 feat: admin password reset link for users (#70464)
* feat: admin password reset link for users

* fixup! add missing dep to modules.edn

* fixup! response schema position

* fixup! reset e2e tests

* fix: store temporary password in Redux after no-SMTP password reset

The handleResetConfirm function called updatePassword via RTK Query but
never dispatched storeTemporaryPassword, so the temporary password modal
never appeared.

* fix: replace smart quotes with straight apostrophes in password reset modal

The modal title and body strings used Unicode RIGHT SINGLE QUOTATION MARK
(U+2019) instead of ASCII apostrophe, causing E2E tests to fail on text
matching.

* fix: correct reset URL assertion in e2e test

The test expected "password-reset" but the actual URL path is
"reset_password".
2026-03-19 10:30:32 -05:00
Braden Shepherdson
90042b1f02 [MBQL lib] User docs for aggregation functions (#70515)
Part of QUE2-366.

Adds user-facing documentation for aggregations functions in `lib.core`.
2026-03-19 14:26:22 +00:00
Kamil Mielnik
55144d12be GDGT-2001 Get rid of VisualizationSettingDefinition["default"] (#71015) 2026-03-19 14:08:16 +00:00
Stas Gavrylov
91ca661215 GDGT-2037: Fix CssVarsDeclarationPlugin crashing dev server on missing files (#71139)
* Fix CssVarsDeclarationPlugin to not break on build if file is missing

* Fix path to color-keys file

* Add CssVarsDeclarationPlugin warning comments to referenced source files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:03:29 +00:00
github-automation-metabase
b42f3332c0 Auto-update documentation for master (#71128)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-19 09:32:36 -04:00
Nicola Mometto
4937134c3e Batch metabase_table update migration (#70996)
* fix: batched metabase_table update on data_layer

* don't replace inline

* preserve

* no need for rollback in liquidbase

* run outside of a transaction

* runInTransaction:false
2026-03-19 12:05:42 +00:00
Jakub Chodorowicz
ebbc0adc70 display sql transforms errors in editor (#71092)
* update setupCardDataset to use named params

* display sql transform errors in editor

* improve mock data in test

* use isObject helper
2026-03-19 11:10:33 +00:00
Nicolò Pretto
45cd62fe3e remove claude from mise as it's not a required tool (#71138) 2026-03-19 10:22:47 +01:00
Jakub Chodorowicz
2d250a7a71 change incremental transform copy (#71103) 2026-03-19 09:59:14 +01:00
Chris Truter
7ecba8f6d4 Create table entries for transform targets on save (#70552) 2026-03-19 08:09:03 +00:00
Aleksandr Lesnenko
e53b32e245 stacked series (#70682) 2026-03-19 00:49:25 +00:00
Edward Paget
48d1a7c36e fix: handle recycled jetty http response objects (#70674)
* fix: handle recycled jetty http response objects

In the streaming response handler. Make sure that the response object is
both committed and that its AsyncContext has not been timedout.
Attempting the write after the timeout results in an NPE.

* fixup! missing reify method

* make async-context-completed? private
2026-03-18 16:37:35 -05:00
Anderson
d2406bf64b Fix aria-expanded on dashboard filter trigger button (#70543) (#70973)
* Fix aria-expanded on dashboard filter trigger button (#70543)

Closes https://github.com/metabase/metabase/issues/70543

Move aria-expanded from a wrapper div to the actual trigger button element
for dashboard filter popovers. Mantine's Popover.Target injects
aria-expanded via cloneElement onto its direct child. Previously, a Box
wrapper div was the direct child, so aria-expanded landed on a
non-interactive div instead of the button. This restructures the
component hierarchy so ParameterValueWidgetTrigger (which renders as a
button) is the direct child of Popover.Target, and moves the Sortable
wrapper outside the Popover.

1. Open a dashboard with filter parameters
2. Inspect the filter trigger button element in the DOM
3. Verify aria-expanded is on the button element (not a wrapper div)
4. Click the filter to open the popover and confirm aria-expanded
   toggles to true on the button

- [x] Tests have been added/updated to cover changes in this PR

* Wrap dashboard filter items in a list container for a11y
2026-03-18 17:30:40 -03:00
Kevin Kelleher
c62b32e78f Fix pivot text overlapping when next header column is collapsed (#71104) 2026-03-18 15:49:56 -04:00
Noah Moss
241e1fb189 Better error logging for slackbot (#71098) 2026-03-18 14:23:36 -05:00
Rodrigo López Dato
db25f8fa80 Docs: improve embedding appearance theming section (#70967)
* Docs: improve embedding appearance theming section

Rewrite the basic theming section for clarity: rename to "Dark mode and
light mode", simplify the explanation, and preserve the old
#basic-theming anchor for existing links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update docs/embedding/appearance.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-03-18 18:35:09 +00:00
Ben Grabow
86d1b95df0 Bgrabow/ci test repl mage task (#71025)
* ci-test-repl mage task

* Use ci port map to set port. Include junit name in job string

* Move to bgrabow

* Add dry-run mode

* task! wrapper to support helptext
2026-03-18 18:18:33 +00:00
Jeff Bruemmer
ee6203aa6e docs - agent demo link (#71074)
* agent demo link

* Optimized 1 images, saved 125.8 KB (45.1% smaller)

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-03-18 18:03:17 +00:00
Anderson
4b7056a383 Make it clearer why transforms can't be created in read-only mode (#71051)
test: update tests for read-only mode transform creation UI changes

Update E2E tests to verify:
- Create transform button is disabled with explanatory tooltip in read-only mode
- New transform pages show not found message when accessed directly in read-only mode
2026-03-18 13:58:32 -03:00
Nathan Voxland
25100c1310 Allow linear to trigger repro-bot (#71049) 2026-03-18 09:03:46 -07:00
Alex Yarosh
2f7a83ddc5 docs: new incremental transforms (#71080)
* incremental transforms

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-03-18 11:21:06 -04:00
Ben Grabow
0abb871d3f Fix flaky metabase-enterprise.dependencies.api-test (#71024)
* Drain the single-threaded async executor to ensure all pending dependency work completes before model cleanup deletes cards, avoiding lock timeouts.

* Use fresh-dependency-async-executor-fixture on every test
2026-03-18 10:01:34 -05:00
Eric Normand
693550cf45 Correctly hide/show card filters based on permissions (#70980)
Backend (query_processor/dashboard.clj): Added an explicit view-data permission check using most-permissive-database-permission-for-user. This returns 403 when a user has no view-data access, taking precedence over parameter validation errors (400).

Frontend (DashCardVisualization.tsx): Decoupled the three concerns:

* Inline parameters render when inlineParameters.length > 0 AND the user has view access (no 403 on the card result)
* DashCardMenu (download button) renders when DashCardMenu.shouldRender() is true (requires canEditQuestion or canDownloadResults)
* 403 from backend hides both inline params and menu — no point showing UI for data the user can't access
2026-03-18 09:35:17 -05:00
Ryan Laurie
8255a879de Parameterize runners (#71077)
* Use custom runners

# Conflicts:
#	.github/workflows/cross-branch-migrations.yml
#	.github/workflows/pre-release.yml
#	.github/workflows/tusk-sanity-check.yml

* more updates

---------

Co-authored-by: Nemanja <31325167+nemanjaglumac@users.noreply.github.com>
2026-03-18 08:24:12 -06:00
Sébastien
ea2e642c82 Fixed flaky e2e test (#71019) 2026-03-18 15:00:06 +01:00
github-automation-metabase
3bfd0aa9bf Auto-update documentation for master (#71058)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-18 08:41:53 -04:00
Uladzimir Havenchyk
f45dbe78a1 chore: update formatting (#71072) 2026-03-18 13:04:05 +01:00
Kevin Kelleher
43ab4dbb8d Allow grid columns in Detail visualization to grow and shrink (#70964) 2026-03-18 07:49:40 -04:00
Jakub Chodorowicz
80d08cce82 use array/list for sources table in transforms (#70100) 2026-03-18 11:11:24 +01:00
Fraser
7e5435f6f1 Dev 1662 move libcolors into UI (#70754) 2026-03-18 22:52:16 +13:00
Kamil Mielnik
3c229eb38d GDGT-1998 Get rid of VisualizationSettingDefinition["marginBottom"] (#71004) 2026-03-18 15:59:11 +07:00
Nathan Voxland
4ca03e17ef Took out now-unneeded search delay 2026-03-18 02:05:25 -05:00
Kamil Mielnik
e271bc5e52 GDGT-1995 Get rid of VisualizationSettingDefinition["disabled"] (#71000) 2026-03-18 14:00:46 +07:00
Nathan Voxland
ec2b0f38ae Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	src/metabase/analytics/prometheus.clj
2026-03-18 01:46:46 -05:00
Nathan Voxland
2bad85564e Publish messages after an appdb transaction. Plus batch them still for 100ms to handle times we don't really have a transaction to avoid so many small batches 2026-03-18 01:45:26 -05:00
Cam Saul
f5eeabb4be Rework Pivot QP to add pivot-grouping in post-processing (#70986)
* Rework Pivot QP to add `pivot-grouping` in post-processing

* PR feedback

* Fix MongoDB test failures

* Fix test failures

* cljfmt

* Fix calculating pivot group for queries with remaps

* cljfmt

* Test fix 🔧

* Test fix 🔧

* Delete unused code
2026-03-18 01:29:20 +00:00
Anderson
f2164af918 Add snowplow events when creating new job (#70279)
* Add snoplow events when creating new job

* Fix e2e
2026-03-17 21:05:09 -04:00
Anderson
832e71aa46 Add aria-level attribute to dashboard title heading (#70985)
* Add aria-level attribute to dashboard title heading

Closes https://github.com/metabase/metabase/issues/70544

### Description

Dashboard title elements with role="heading" now include the aria-level
attribute set to 1, properly indicating they are primary headings. This
improves accessibility for screen reader users by establishing the correct
heading hierarchy.

The fix adds aria-level={1} to the Box component in DashboardHeaderView
that already has role="heading". This ensures screen readers can properly
navigate the heading structure of the dashboard page.

### How to verify

1. Open any dashboard in Metabase
2. Inspect the dashboard title element in browser DevTools
3. Verify the heading has both role="heading" and aria-level="1"
4. Test with a screen reader (e.g., NVDA, JAWS) to verify it's announced
   as a level 1 heading

Alternatively, run the new unit test:
```bash
bun jest --testPathPatterns="DashboardHeader/tests/common.unit.spec"
```

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

* Clean up
2026-03-17 20:45:09 -03:00
Sloan Sparger
6826140380 [Metabot] Slackbot (#68473)
* wip

* clean up and move secrets to settings

* validate incoming slack requests and better sending of messages / processing responses

* get ai response working, make slack app an agent, fetch threads

* add loading / thinking state

* image uploading and clean up

* add test coverage for validation of slack requests

* add test coverage for endpoints only being available with metabot token feature

* add test coverage for user messages

* fix image uploads not working

* add test coverage for messages with visualizations

* fix convo history

* allow for rendering adhoc questions and surrounding the static viz with padding

* Re-enable +auth middleware for endpoints in metabase-enterprise.metabot-v3.api

* Ensure user has linked slack and metabase accounts before sending messages

And send them an ephemeral message with a (currently invalid) link to authorize

* Add some more repl testing comments

* dev comments: fix assert when updating manifest and encourage env vars for dev secrets

* Use request/with-current-user rather than binding api/*current-user* directly

This is the preferred way to set the user and handles binding things like api/*is-superuser?* and
api/*current-user-permissions-set* as well.

* smol refactor to clean up process-user-message

* Fix kondo lint warning about undeclared channel module dep

* Fix reflection warning for metabase.server.streaming_response/StreamingResponse

* Fix reflection warning in user-message-with-visualizations-test

* Use :on-complete handler to capture lines in make-ai-request

* Make all defs except endpoints and routes private

* Rename client :bot-token to :token

Currently only used for endpoints that expect a bot token, but in principal these could be used for other endpoints
that might expect, e.g. an app config token to update the app manifest.

* fix builds

* throw down a basic settings ui page

* validate slack bot token

* fix failing verification step

* refine sso flow, update temp admin form to collect info we need

* ensure slackbot is only enabled if setup is complete

* add instructions to add bot image

* Re-enable user-not-linked-sends-auth-message-test

This deftest got accidentally slurped into the preceding one in 07eb42c76f4. Extract it back out into the toplevel.

* Fix kondo whitespace lint

* temp staging deploy fix?

* BOT-853 Add malli schemas to slackbot defendpoints

* Ensure site-url is configured and fix failing test

* Add reminder to set MB_SLACK_CONNECT_ENABLED

* make image rendering larger

* Ensure :test-users are initialized in slackbot tests

* Fix busted tests due to missing site-url

Site-url needs to be added to with-slackbot-setup and do-with-setup-override since I added site-url to
metabase-enterprise.metabot-v3.api.slackbot/setup-complete?

These tests passed when run from the REPL because I had site-url configured locally, but failed when run from the cli.

* make setup instructions clearer

* clean up dev comment form

* BOT-852 Add malli schemas for slack event types

* improve auth flow

* oops

* Rename SlackHandledMessageEvent to SlackKnownMessageEvent

And fix the order of types in SlackKnownMessageEvent

* improve settings page

* WIP csv uploads

* tweaks

* tweaks

* fixes & cleanups

* Ad-hoc querying for slackbot (#69315)

* basic ad-hoc query support

* fix capabilities

* cleanup + another test

* more test fixes

* fix some kondo

* move middleware auth tests to a new EE namespace

* minor fixes

* fix tests

* remove unneeded transforms capability

* remove some debug code

* [Metabot] Slackbot channel support (#69391)

* channel support

* ignore edited messages

* add tests

* lint fix

* lint fix

* pr feedback

* test fix

* skip channel messages

* default enable slack sso

* Fix failing metabase.core.modules-test/module-uses-should-be-sorted-test

* Require user to be active in slack-id->user-id

* metabot/slackbot - Adjust CSV upload support (#69832)

* init

* remove debug def

* BOT-984 Add slack channel support to create-dashboard-subscription tool (#69371)

* Add slack channel support to create-dashboard-subscription tool

* Fix render-html-to-png

We recently added a new 3-arg arity, but were only passing along the :content of the ::body/RenderedPartCard rather
than the full map, resulting in a malli schema error due to dropping the required :attachments key for any callers of
the 2-arg arity, e.g. when trying to send a slack notification.

    clojure.lang.ExceptionInfo: Invalid input: {:attachments ["missing required key, got: nil"]}
	at metabase.channel.render.png$fn__107479$fn__107505.invoke(png.clj:124)
	at metabase.channel.render.png$fn__107479$render_html_to_png107478__107482.invoke(png.clj:128)
	at metabase.channel.render.png$fn__107479$fn__107505.invoke(png.clj:124)
	at metabase.channel.render.card$fn__108322$png_from_render_info108321__108323.invoke(card.clj:302)
	at metabase.channel.render.card$fn__108322$fn__108325.invoke(card.clj:298)
	at metabase.channel.impl.slack$part__GT_sections_BANG_.invokeStatic(slack.clj:117)
	at metabase.channel.impl.slack$part__GT_sections_BANG_.invoke(slack.clj:87)

* Add find-cached-slack-channel-or-username

* Validate slack-channel in create-dashboard-subscription

Serves the dual purpose of making sure the channel exists and also normalizing the name to the display-name with
leading # which is how channels selected in the UI are stored.

* Drop support for email subscriptions

Since this is only going to be used from the slackbot profile, we'll only support sending subscriptions to slack
channels for now.

* handle-agent-error in create-dashboard-subscription

* Add create-pulse-with-perm-checks! and call that from create-dashboard-subscription tool

To ensure the same permission checks and other logic is used as when creating a pulse from the UI or API.

* Do no export pulse.models.create-pulse! from pulse.core

The only consumer was metabot's create-dashboard-subscription which now calls create-pulse-with-perm-checks! instead.

* BOT-985 Add create-alert metabot tool for slackbot (#69533)

* Add create-alert metabot tool

To allow the agent to create alerts for a given card on a given schedule, similar to the existing
create-dashboard-subscription tool.

* Add notification.api/create-notification! and call it from metabot_v3.tools/create-alert

This ensures that create-alert does the same perms checks and send the same verification email and notifications as
the main api endpoint.

* Improve ::create-alert-arguments malli schema

Use :multi with :dispatch on :channel_type to make it clear that email is required when :channel_type is "email" and
likewise :slack_channel is required when :channel_type is "slack"

* Destructure email in create-alert args

* handle-agent-error in create-alert

* Drop support for email subscriptions

Since this is only going to be used from the slackbot profile, we'll only support sending subscriptions to slack
channels for now.

* Add api test for create-alert metabot tool endpoint

* Fix bad conflict resolution from rebase

* BOT-1026 Pass slack-channel-id in the ai-service request context (#69828)

* BOT-1026 Pass slack-channel-id in the ai-service request context

For ai-service requests originating from slackbot, send along the slack channel id. The ai-service tools will also be
updated to use this channel id when creating dashboard subscriptions or alerts.

* Add make-ai-request-args-test

* Slackbot table output format (#69511)

* WIP - table ouptut for Slack metabot

* lint

* WIP support for pre-fetched data

* WIP

* lint

* add slack-connect-enabled to do-with-other-sso-types-disabled

* fix another test

* change slack-connect-enabled default to false

* simplify approach

* Misc fixups

* more cleanup

* fix another test

* small readability improvements

* Move some of the table data preparation stuff to a new namespace to share with  existing slack/email rendering code

* fix modules lint

* extract table-block components and include in thread history

* revert query results changes (for now) and just drive slack table formatting via viz type selection

* truncation message

* truncation message test case

* rollback more execute-query stuff

* fix build

* temporarily comment out extract-table-blocks stuff

* fix test

* Merge slackbots and settings pages (#69782)

* wip

* more progress

* conslidate manifest endpoints

* remove slack-token

* handle missing scopes case

* respect slackbot feature toggle in event handler

* other-sso-enabled? now takes into account sso mode

* new slack app-info endpoint for getting helpful metadata for the connected slack app, update links on FE to more direct location in slack

* replaced "metabot-slack-bot-enabled" with "slack-connect-enabled"

* misc. small fixes

* move slack scopes endpoint to app-info endpoint, update copy, misc ui improvements

* fix slack events api endpoint to still ack events if metabot later becomes disabled

* first step now configured to show obscured token, remove old modal component that was unused

* improve app icon section

* small design pass and linkage improvement to step 3

* new settings endpoint for metabot slackbot settings, updated FE component and form validation

* improve slack bug channel input, also update api endpoint so that slack setting values can be set seperately

* obfuscate client secret and signing secret

* improve the webhooks page a bit

* inline save / delete btuton for slack oauth token input

* allow removing metabot related slack settings in the ui

* self-review

* fix kondo

* fix some be tests

* test fixes, link fixes, page reorg

* poll for updates

* fix some e2e tests

* show info button w/ bot token info on hover

* updated profile image for slackbot

* fix be tests

* fix unit tests

* fix be test

* add unit test converage for base setup

* remove SlackSettingsPage which had duplicate tests

* add test coverage for settings endpoint

* new settings ui tests

* remove todo comment

* set default icon / name for slackbot

* make slack-get match slack-post response format

* show api errors better in slack metabot form

* impl set-many feedback

* fix requiring resolve code smell

* log error based on feedback

* handle error for app-info

* Slackbot streaming (#69947)

* [wip] Slackbot streaming

* simplify, lint

* Fix tests

* Use a volatile

* fix tests

* refactors, cleanup

* more cleanup

* fix tool name

* Better stream-related error handling + tests

* add another test

* properly destructure api calls for streaming / auth

* fix streaming not having icon_url set and make sure that channel level @mentions has the bot reply with auth request at channel level too

* embarrassing

* Rework + simplify streaming using an agent to try to reduce burstiness

* prevent tests from clearing out setting values

* Add a thinking... placeholder before stream starts +  do initial Slack requests in futures

* rip out overrides, streaming api reverts the defaults so it flashes images if they differ from the one saved for the slack app

* [Slackbot] Render unsupported static viz as tables (#70077)

render unsupported static viz as tables

* Slackbot test refactor + fix overwriting encrypted settings (#70113)

* Fix encryption overwriting in tests; small cleanup

* more refactor

* [Slackbot] Modularize (#70130)

modularize

* [Slackbot] Adds check to prevent replay attacks (#70081)

* prevent relay attack

* fix syntax issue

* pr feedback

* lint fix

* [Slackbot] Prevent channel response (#70136)

* add more tests, refactor

* bit more clean up

* ignore channel messages without @mention

* simplify, fix tests

* add file mock to tests

* move bot id fetch

* Migrate slack-connect SSO to dedicated /auth/sso/slack-connect URL pattern

Move slack-connect from the old unified /auth/sso multimethod dispatch to
dedicated GET /auth/sso/slack-connect and GET /auth/sso/slack-connect/callback
endpoints, aligning with the pattern used by custom OIDC providers.

* fix oauth flow requiring user page refresh

* kick ci

* fix threading for auth message in dms

* Report QP errors to Slack, and run queries off the main thread (#70124)

* WIP - surface QP errors, don't block queries on text stream

* simplifications

* fix up a couple other tests that were corrupting values

* try to fix test

* cleanup

* more cleanup

* more cleanup

* Fix test

* small simplification

* more fixes

* timeouts

* simplify comment

* call shutdown-agents at the end of the core shutdown routine

* [Slackbot] Stable conversation ids (#70281)

* make convo ids stable for slack conversations

* fix lint

* fix missing paren

* Update enterprise/backend/test/metabase_enterprise/metabot_v3/api/slackbot_test.clj

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>

---------

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>

* fixup! set a proper response code in safari

* Slack SSO info logs in initiate & callback endpoints

* make slack user look up deterministic

* log actual oidc cookie

* [Slackbot] Better static viz sizing (#70288)

* make slack user look up deterministic

* calc size of static viz based on display type

* fix doc string

* fix tests, add sankey support

* fix lint

* make metabot self-aware... of @mentions

* add some truncation logic for slack blocks + long cell values

* Improved titles for slackbot visualizations; misc other fixes (#70396)

* support context text for results

* viz captions with links; hold viz results until stream finishes

* tests; remove separate caption & description fields

* grab bag of fixes

* strip out user mention stuff from this branch

* caption->title

* fix build

* fix test

* polish

* some escaping logic for markdown links

* fix filename

* Slackbot feedback buttons (#70280)

* WIP slack feedback buttons

* wire up feedback buttons

* tests

* feedback modal

* revert back to a single hm call

* fix parens

* revert an unexpected change

* small fixes

* fix tests

* tweaks

* fix rebase

* Update enterprise/backend/src/metabase_enterprise/metabot_v3/api/slackbot/streaming.clj

* fix rebase

* [Slackbot] Enrich chat history (#70408)

* poc

* move code around

* fix tests, clean up logs

* clean up

* fix

* automated review feedback

* do not store messages on error

* test coverage

* lint fix

* Ensure we respect slack api rate limits (#70409)

* try to respect slack streaming rate limits

* tests

* simplify

* lint

* try to fix tests, some tweaks

* bump ci

* [Slackbot] Better auth messages (#70465)

* improve auth message responses

* better auth messages

* pr feedback

* Split slackbot DM and channel response paths, embed viz in message (#70531)

* Viz delivery refactor for slackbot

* simplify

* more refactor

* more test porting

* Update enterprise/backend/src/metabase_enterprise/metabot_v3/api/slackbot/channel.clj

* condense some code

* fix tests

* fix stale session bug

* Slackbot message deletion (#70533)

* Slackbot message deletion

* Tests

* Fix tests

* minor cleanup

* add user_id to metabot_message to drive deletion permissions

* balence parens

* fix parens

* feedback

* fix failing migration tests

---------

Co-authored-by: Sloan Sparger <sloansparger@gmail.com>

* Fix slackbot feedback acknowledgement (#70642)

* fix slackbot feedback acknowledgement

* simplify docstring

* remove feedback acknowledgement entirely

* Add slackbot prometheus metrics (#70654)

* add slackbot prometheus metrics

* simplify

* lint

* remove todo comment

* [Slackbot] Cleanup (#70692)

* move migrations to v60 file

* clean up auth debug logging

* move slackbot into its own module and split up the core test file

* fix whitespace lint

* [Slackbot] Fancy (#70729)

* mostly working w/o proper saving of messages

* backfill slack_msg_id

* Minor tweaks: swap volatiles for atoms, switch away from deprecated StringBufferInputStream

* address libor's comments

* fix tests - wrap async functions with bound-fn*

* oops, fix last test

* fix reflection issue

* whitespace chagne to kick new jar build

* update subscription tool + tests

* fix .clj-kondo/config/modules/config.edn resolution and related failing tests

* [Slackbot] Port ai service (#71026)

* main port

* port https://github.com/metabase/ai-service/pull/626/changes

* clean up

* kondo fix

---------

Co-authored-by: Mike Appleby <86076+appleby@users.noreply.github.com>
Co-authored-by: Tyler Plude <tsplude@gmail.com>
Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
Co-authored-by: Noah Moss <noahbmoss@gmail.com>
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
2026-03-17 23:23:40 +00:00
Riley Thompson
47ff6b70a6 Pin google auth dependency to avoid driver mismatches (#70958)
* pin dep

* trigger ci tests

* update test
2026-03-17 20:59:53 +00:00
Nathan Voxland
7ab0784977 ReproBot Improvements (#70990) 2026-03-17 15:57:47 -05:00
Jeff Bruemmer
e8bc1db487 docs - remote sync providers (#70969) 2026-03-17 16:16:15 -04:00
Uladzimir Havenchyk
527a4d67e9 chore: upgrade underscore (#70778) 2026-03-17 22:58:29 +03:00
Nick Fitzpatrick
b0deebf2b6 Clear ChartSettingSelect display value on remove (#70957) 2026-03-17 15:57:55 -04:00
appleby
09d9a4a446 BOT-1131 Rename :snake_case keys to :kebab-case in metabot stats (#71027) 2026-03-17 19:55:33 +00:00
Fraser
08b84f4b16 Lift data_grid.js up to shared (#70755)
* Lift data_grid.js up to shared

     data_grid.js is in lib/lib but imports makeCellBackgroundGetter from table_format in shared/visualizations, causing a lib/lib → shared/visualizations boundary violation. data_grid.js is not used by
     anything in lib — all consumers are in shared/visualizations, feature/dashboard, and visualizer. table_format already lives in shared/visualizations and only depends on basic/ui colors.
2026-03-18 08:33:39 +13:00
Fraser
829b34e44a Remove metadata re export from reference (#70561) 2026-03-18 08:32:01 +13:00
Nathan Voxland
5d6c208865 Improve search endpoint performance with many disabled tables (#70982) 2026-03-17 13:09:19 -05:00
Jeff Bruemmer
6d37120fb9 docs - Fix typo in JWT group mapping documentation (#71017)
Fix typo in JWT group mapping documentation
2026-03-17 11:52:02 -04:00
Sébastien
2390c28119 Fixed metrics not being translated in guest embeds (#70484) 2026-03-17 16:44:59 +01:00
Cam Saul
5217327fb9 Fix running app DB with MariaDB 10.6 official image in CI (#70824)
* Fix running app DB with MariaDB 10.6 official image

* Update all MariaDB configs

* Use custom Docker image 🔧

* Loosen dependence on quoting format of mysql/mariadb error messages

* Use tz aliases supported in mariadb 12

* Run tests in series. Use fresh H2 DB.

---------

Co-authored-by: Ben Grabow <ben.grabow@metabase.com>
2026-03-17 14:52:37 +00:00
Chris Truter
b215b0ff3d Fix mage mise-diagnosis (#71012) 2026-03-17 14:34:13 +00:00
Mihael Konjević
9796110af3 Ai service port (#68463)
* Experiment with communicating with LLMs in Clojure

* Libor comments

* switch to new openai /v1/responses api, check for structured output support

* support for claude to show how different adapters are

* linter fixes

* Implement native Clojure agent for MetaBot v3

This commit implements a production-ready native Clojure agent loop that
replaces the external Python AI Service with an in-process implementation,
leveraging the existing llm-inside streaming infrastructure.

Key Components:
- agent/core.clj: Main agent loop with iteration control and streaming
- agent/memory.clj: Conversation state and step tracking
- agent/messages.clj: Message formatting and LLM communication
- agent/profiles.clj: Profile configurations (embedding, internal, transforms)
- agent/tools.clj: Tool registry with 13 wrapped tools

Integration:
- api.clj: Feature-flagged routing via use-native-agent setting
- settings.clj: New use-native-agent boolean setting (default: false)

Benefits:
- Direct Toucan2 database access (no HTTP round-trips)
- Single JVM process deployment
- Lower latency for tool execution
- Unified logging and error handling
- Reuses 80%+ of existing streaming infrastructure

Test Coverage:
- 5 test files with comprehensive coverage
- All tests passing (133 total assertions)
- Unit tests for memory, messages, profiles, tools
- Integration tests for agent loop with mocked LLM

The implementation is production-ready and can be enabled via feature flag
for gradual rollout and validation against the Python service.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Integrate Phase 2A: Prompts & Context System into agent loop

This commit completes Phase 2A of the native Clojure agent implementation,
integrating the templated prompt system with context enrichment into the
main agent execution loop.

## New Features

### Prompt System (prompts.clj)
- Selmer template loading with caching
- SQL dialect instruction injection (14 dialects supported)
- Tool instruction extraction from docstrings
- System message template rendering with context variables

### Context Enrichment (user_context.clj)
- Timezone-aware time formatting
- SQL dialect extraction from context
- Viewing context formatting for all types:
  - Adhoc queries (notebook editor)
  - Native SQL queries with error context
  - Transforms with source information
  - Code editor with buffer/cursor/selection details
  - Entity details (tables, models, questions, metrics, dashboards)
- Recent views formatting with relevance hints
- Full context enrichment pipeline for template variable injection

### Resource Files
- 3 system prompt templates (embedding, internal, transform-codegen)
- 14 SQL dialect instruction files
- All templates support dynamic context injection

## Integration Changes

### Agent Core (core.clj)
- Updated build-messages-for-llm to accept context, profile, and tools
- Integrated system message building with enriched context
- Fixed pre-existing async blocking issue in run-llm-with-tools
  (changed from blocking a/<!! to returning channel for non-blocking a/<!)
- Agent now builds fresh system messages with context on each iteration

### Messages (messages.clj)
- Updated build-system-message to use templated prompts
- Accepts context, profile, and tools parameters
- Calls prompts/build-system-message-content for rendering

### Profiles (profiles.clj)
- Added :prompt-template mapping to all three profiles
- Maps profile IDs to template files in resources/metabot/prompts/system/

## Tests

All Phase 2A functionality is comprehensively tested:
- prompts-test: 6 tests, 46 assertions ✅
- user-context-test: 5 tests, 81 assertions ✅
- messages-test: 3 tests, 47 assertions ✅
- profiles-test: 1 test, 36 assertions ✅

Total: 15 tests, 210 assertions passing

Note: core-test integration tests have pre-existing failures due to blocking
calls in self/core.clj tool-executor-rff (line 116), which existed before
this change. The async pipeline architecture issue is tracked separately.

## Architecture

The agent now follows this flow on each iteration:
1. Enrich raw context (user_context/enrich-context-for-template)
2. Load and render system prompt template (prompts/build-system-message-content)
3. Build full message array with system message + history
4. Execute LLM call with enriched context
5. Process tool calls and responses
6. Repeat until completion

This matches the Python implementation's prompt and context system while
leveraging Clojure's functional architecture.

* Add Selmer dependency for template rendering

Selmer v1.12.70 provides Jinja-like templating for Clojure,
used by the Phase 2A prompts system for rendering system messages
with dynamic context variables.

* Fix async blocking issue in agent loop by using pipeline-blocking

The tool-executor-rff reducing function blocks in its completion arity
to wait for tool results. Using a/pipeline causes 'Invalid blocking call
in dispatch thread' errors because the regular pipeline uses a fixed
thread pool that doesn't allow blocking.

Solution: Use a/pipeline-blocking instead, which uses a separate thread
pool designed for blocking operations. This allows the tool executor's
completion arity to safely block while waiting for tool results.

Fixes the core-test integration test failures.

* Implement Phase 2B: SQL Query Tools

Add four SQL query manipulation tools to enable the agent to create, edit,
and search SQL queries:

New Tools:
- create_sql_query: Create new SQL queries with validation
- edit_sql_query: Apply structured edits (replace, append, insert, etc.)
- replace_sql_query: Replace SQL content entirely while preserving metadata
- sql_search: Search for SQL queries by content with relevance ranking

Features:
- Direct Toucan2 Card model access (no HTTP round-trips)
- Database and permissions validation
- Structured edit operations (replace, replace-all, append, prepend, insert-after, insert-before)
- Search with ranking by name match, description match, SQL position, and recency
- Integration with existing agent tool registry
- Added to metabot-internal profile and new metabot-sql-only profile

Testing:
- Comprehensive test coverage for all SQL tools
- Integration tests for full workflow (create → edit → search)
- All tests passing (18 assertions, 0 failures)

Architecture:
- Follows existing tool pattern (mu/defn with Malli schemas)
- Returns structured output for agent state tracking
- Error handling with agent-error? flag for LLM-friendly messages

Phase 2B complete. Ready for Phase 2C: Visualization Tools.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Fix SQL tools to handle lib/query format

Fixed multiple issues with SQL tools not handling the transformed
lib/query format when Card models are read from the database:

## Issues Fixed

1. **extract-sql-content not finding SQL**: Card dataset_query transforms
   from {:native {:query "SQL"}} to {:stages [{:native "SQL"}]} when read.
   Updated extract-sql-content in all SQL tools to handle both formats.

2. **OffsetDateTime vs Date**: The rank-result function in sql_search
   called .getTime on timestamps, but Toucan2 returns OffsetDateTime.
   Added instanceof check to convert appropriately.

3. **Missing visualization_settings**: Test code using t2/insert! needed
   :visualization_settings {} field (database constraint).

4. **Test permissions**: Wrapped all test code with mt/with-current-user
   to provide proper permission context.

5. **Fixed typo in sql_search**: Changed accessible-cards variable reference
   from undefined to all-cards.

## Files Changed

- edit_sql_query.clj: Handle both lib/query and legacy formats
- replace_sql_query.clj: Handle both lib/query and legacy formats
- sql_search.clj: Handle both formats + OffsetDateTime conversion
- sql_tools_test.clj: Add visualization_settings, fix permissions,
  add clojure.string alias, fix indentation

## Test Results

All 19 assertions passing (4 test functions):
- edit-sql-query-test: 4 edit types tested
- replace-sql-query-test: Replace with metadata preservation
- sql-search-test: Search, filter by database, limit parameter
- integration-create-edit-search-test: Full workflow

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Add read_resource tool for fetching Metabase resources via URIs

Implement the foundational read_resource tool that provides unified
interface for fetching detailed information about Metabase resources
using URI patterns. This tool implements the "Context Engineering with
Links" pattern where URIs serve as lightweight, token-efficient
references that can be fetched on-demand at the appropriate detail level.

Supported URI patterns:
- metabase://table/{id} - Basic table info
- metabase://table/{id}/fields - Table structure with fields
- metabase://table/{id}/fields/{field_id} - Specific field details
- metabase://model/{id}/fields - Model structure with fields
- metabase://metric/{id}/dimensions - Metric dimensions
- metabase://transform/{id} - Transform details (not yet implemented)
- metabase://dashboard/{id} - Dashboard details (not yet implemented)

Key features:
- Parses metabase:// URIs and routes to appropriate handlers
- Supports fetching multiple resources in parallel (max 5)
- Handles field IDs with slashes (e.g., c75/17)
- Returns formatted XML-like output for LLM consumption
- Provides detailed error messages for invalid URIs

This tool is critical for:
- Enabling agents to get more context about resources on demand
- Supporting workflows where search returns URIs that agents fetch later
- Reducing token usage by deferring detail fetching until needed

Changes:
- Created read_resource.clj with URI parsing and resource handlers
- Added read-resource-tool wrapper in tools.clj with Malli schema
- Updated all 4 profiles to include read_resource tool
- Added comprehensive tests for URI parsing and resource fetching

Tests: 24 assertions, 0 failures

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Implement Phase 2C chart tools, 2F profiles, and fix async blocking

Phase 2C - Chart Tools:
- Add create_chart tool to create visualizations from queries
- Add edit_chart tool to modify existing chart types
- Register chart tools in agent tools registry

Phase 2F - Profiles & Templates:
- Port sql-querying-only.selmer from Jinja2 (fixes broken :metabot-sql-only)
- Port metabot-next.selmer template
- Port natural-language-querying-only.selmer template
- Add :metabot-next, :metabot-nlq-only, :metabot-beta-customer profiles

Async Blocking Fix:
- Use a/thread instead of a/pipeline-blocking in run-llm-with-tools
- tool-executor-rff uses a/<!! in completion arity which cannot run in go-blocks
- Synchronous transducer application in thread context is now aligned with self code
- Fix stream-parts-to-output! and finalize-stream! to use a/>! in go blocks
- Fix api.clj syntax error with metadata on string literal
- Update tests to generate proper Claude raw SSE format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add AI SDK v4 line protocol output format for native agent

The Python ai-service outputs a specific line protocol format that the
frontend expects. This adds the conversion layer to output the same format
from the native Clojure agent.

Format examples:
- 0:"text content"  - Text (JSON-encoded string)
- 2:{"type":...}    - Data parts
- 3:"error"         - Errors
- 9:{"toolCallId":..., "toolName":..., "args":...}  - Tool calls
- a:{"toolCallId":..., "result":...}  - Tool results
- d:{"finishReason":"stop", "usage":{...}}  - Finish message
- f:{"messageId":...}  - Start message

Changes:
- Add format-* functions for each part type in self/core.clj
- Add aisdk-line-xf transducer for batch conversion
- Export new functions via self.clj
- Update api.clj to stream parts in line protocol format
- Add comprehensive tests for all format functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix native agent loop for multi-turn conversations with tools

Key fixes:
- Fix premature loop exit: Continue when tool calls present, regardless of text
- Fix Claude API integration: Extract system message separately, pass via :system param
- Fix tool name mismatch: Pass tools as [name, var] pairs so Claude sees registry keys
- Fix message format for tool_use: Use content array format for assistant messages
- Handle START_STEP/FINISH_STEP types in aisdk->messages
- Rename profiles to simpler keys (:embedding, :internal, etc.)
- Add /native-agent-streaming endpoint for testing (bypasses feature flag)
- Add debug logging for message building

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add state management for query/chart IDs in native agent tools

State-dependent tools (show_results_to_user, create_chart, edit_chart) now
look up queries and charts from agent memory by ID instead of expecting raw
query objects. This mirrors the Python AI service pattern.

Key changes:
- memory.clj: Add query/chart storage functions (remember-query, find-query,
  store-chart, find-chart, load-queries-from-state, load-charts-from-state)
- core.clj: Extract queries/charts from tool outputs and store in memory
- tools.clj: Wrap state-dependent tools with memory atom access
- claude.clj: Update schema to accept wrapped tool maps with :fn/:doc/:schema
- self/core.clj: Handle wrapped tool maps in tool-executor-rff
- show_results_to_user.clj: Accept query-id and look up from queries-state

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add metabase:// link resolution for native agent streaming

The native agent now resolves metabase:// URIs in text parts before
streaming to clients. This mirrors the Python AI service's
MarkdownLinkBuffer behavior.

Link types supported:
- metabase://query/{uuid} - Resolves to /question# using stored query
- metabase://chart/{uuid} - Resolves to /question# via chart's query
- metabase://model/{id} - Resolves to /model/{id}
- metabase://metric/{id} - Resolves to /metric/{id}
- metabase://dashboard/{id} - Resolves to /dashboard/{id}
- metabase://question/{id} - Resolves to /question/{id}
- metabase://transform/{id} - Resolves to /admin/transforms/{id}

Changes:
- links.clj: New module for link resolution with markdown parsing
- core.clj: Integrate link processing in stream-parts-to-output!
- Tests for link resolution and streaming integration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix tool result formatting for LLM and link resolution

Key changes:
- Format tool results as XML for LLM consumption (messages.clj)
  - Query results now show query ID clearly: <query id="..." type="query">
  - Chart results include chart ID and reference link
  - This matches Python ai-service format so LLM can extract IDs properly

- Add fallback for chart link resolution (links.clj)
  - When LLM uses metabase://chart/ with a query ID, fall back to
    treating it as a query link
  - Handles common LLM mistake of using wrong link type

- Fix chart extraction logic (core.clj)
  - Charts identified by :chart-id + :query-id (without :query)
  - Distinguishes charts from query results correctly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add InstructionResultSchema pattern for native agent tool outputs

Align Clojure native agent tool outputs with Python AI Service patterns
by wrapping results in <result>/<instructions> XML format for consistent
LLM guidance.

- Add llm_representations.clj with entity-to-XML formatting utilities
- Add instructions.clj with LLM guidance constants for each tool type
- Update messages.clj to use format-with-instructions wrapper
- Add type-specific formatters for search, entity, query, chart results
- Include comprehensive tests for LLM representation functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Align Clojure LLM representations exactly with Python AI Service

Updates tool output formatting to match Python AI Service patterns exactly:

- field->xml: Add quotes around name, database_type attr, ## Description header
- metric->xml: Add collection, default_time_dimension_field, metabase:// URIs
- table->xml: Add database_engine, fully_qualified_name, related_tables section
- model->xml: Use <metabase-model> tag, slug-based fqn, related_tables
- query->xml: Include database_id, query-content, query_results with rows
- Add question->xml, dashboard->xml, collection->xml, user->xml formats
- Add visualization->xml for full chart representation
- Add field-metadata->xml, get-metadata-result->xml for metadata results
- Update search result tags: model→metabase-model, card→metabase_question
- Update instructions.clj with complete Python-matching guidance text
- Update messages.clj to use <metabase-models> tag
- Expand tests to verify Python format compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add auto-navigation and fix tool output handling for native agent

- Add redirect reactions to SQL query tools (create, edit, replace) for
  auto-navigation after query operations
- Add streaming module to convert reactions to AI SDK data parts
- Fix structured output extraction to handle both :structured-output and
  :structured_output key formats (Clojure vs JSON style)
- Add role normalization in message formatting to handle both keyword
  and string roles from frontend
- Include :query key in SQL tool returns for memory storage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Implement AI Service parity for native Clojure agent

This commit adds feature parity between the Clojure native agent and
Python AI service, implementing all phases from the parity plan.

New Tools:
- todo_write / todo_read: Task management with todo_list data parts
- navigate_user: Page and entity navigation with redirect reactions
- ask_for_sql_clarification: SQL clarification with final-response flag
- write_transform_sql / write_transform_python: Transform code editing
- create_autogenerated_dashboard: X-ray dashboard generation
- list_snippets / get_snippet_details: SQL snippet access

Core Changes:
- State data part format: {type: data, data-type: "state", version: 1}
- Finish message format: {type: finish, finish-reason: "stop"|"error"}
- New data part types: todo_list, code_edit, transform_suggestion
- Data part streaming from tool results via :data-parts key
- Final response pattern: tools return :final-response? true to stop loop
- Capability-based tool filtering with tool-capabilities map

Profile Updates:
- internal: Added navigate_user, create_autogenerated_dashboard
- transforms-codegen: Added todo tools, transform write tools, snippets
- sql-only: Added ask_for_sql_clarification, :required-tool-call? flag
- nlq-only: Added navigate_user, create_chart, edit_chart

Tests:
- Comprehensive tests for all new tools (29 new tests, 200+ assertions)
- Updated existing tests for new formats and capabilities

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add streaming link buffer and improve AI service compatibility

Key changes:
- Add markdown_link_buffer.clj for handling links split across streaming
  text chunks (matches Python AI Service MarkdownLinkBuffer behavior)
- Seed agent state with queries from user_is_viewing context
- Support both snake_case and kebab-case keys in context for prompts
- Normalize entity types (keyword/string) in message formatting
- Decode tool arguments from JSON strings when needed
- Add table link resolution (metabase://table/{id})
- Preserve system-instructions when wrapping state-dependent tools
- Fix iteration boundary check (use inc iteration for comparison)
- Gracefully handle unresolvable links by falling back to link text

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Refactor SQL tools to use in-memory state and data parts

Key changes:
- SQL tools (edit_sql_query, replace_sql_query) now operate on in-memory
  query state instead of persisting to database
- Convert tools from reactions to data-parts pattern (navigate_to)
- Add semantic_queries and keyword_queries to search tool schema
- Make edit_sql_query and replace_sql_query state-dependent tools
- Support string query IDs (in addition to int) for memory-based queries
- Extract SQL dialect only from native query context type
- Use streaming.navigate-to-part instead of direct reactions
- Add instructions pattern to SQL tools for better LLM guidance

This aligns the SQL tools with the AI Service's transient query model
where queries exist in conversation state until explicitly saved.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Cleanup

* AI Service cleanup

* Refactor metabot tool registration

* Render LLM representations with Selmer

* Refactor tool result formatting

* define caps by metadata

* Refactor metabot v3 tools namespace

* Route agent tools to core implementations

* Simplify metabot tool wrappers

* factor out core.async as much as possible

* Refactor metabot v3 to use IReduceInit reducibles instead of core.async

- Replace channels with IReduceInit (reducible) pattern throughout
- Standard Clojure transducers work directly: (into [] xf (llm-call {...}))
- Remove core.async dependency from self namespace
- Rename chan? -> reducible?, sse-chan -> sse-reducible
- Rename tool-executor-rff -> tool-executor-xf
- Add malli schemas for agent state, messages, parts
- Simplify agent loop using reducible composition
- Update tests to use reducible patterns

* clarify

* ehhh sideeffect

* fix capabilities/nicer profiles

* tools tests

* api tests

* tools tests

* llm-repr test fixes

* fix profiles.clj

* clj-kondo woes

* is this the last test

* damn

* cljfmt

* fix api test

* update path for e2e tests

* little things

* output text fluidly to a user

* update modules config

* cleaning up links code duplication

* cleanup user context templates

* integration test

* cljfmt

* test

* fix read resource output format

* make clj-kondo happier

* simpler tool executor function

* better error messages from metabot backend

* potentially: ability to reload repl state when js is compiled differently

* metabot error messages and tests

* cleanup agent.messages code/tests a bit

* configurable api urls for llms

* use simple templates more

* format tools to string at their definition

* collecting usage and schema on tool

* system prompts

* datadog observability

* fix modules config

* make clj-kondo happy

* fix read_resource

* fix fe formatting

* more prompt changes

* improve search results tool response

* little cleanups and field-metadata with instructions

* sql dialect

* proper context instructions for sql tools

* report tool args well

* tool result should always have 'result' key

* coerce tool args to json

* good filters validation/errors to llm

* fix construct rendering in system prompt

* fix 'SQL Fixing'

* put queries in the context

* proper rendering for query data

* no :system-instructions

* proper capability check

* handle inline llm errors

* ability to debug llm queries

* fixes to improve llm behavior

* unify query formatting

* accept both variations of db id

* debug for python ai-service

* do not escape instructions

* fix claude usage tracking

* python has no header for tool instructions

* instruct llms to use fq table names

* slight prompt rewording to bring it closer to what benchmarks measure

* fancy field select - reduces amount of tool calls needed

* more clear naming

* simpler date filters handling

* retry logic

* great namespace movement

* no more stacktraces on agent errors

* fix token undercounting

* make sure request cancellation works through with native agent streaming

* Replace raw/endraw tags with safe/endsafe

* Fix issues with the sql profile

* openrouter as main provider

* review comments

* fix test for closing connections

* better schema for incoming messages

* fix agent tests

* cumulative usage from agent loop to reduce need for arithmetics

* clj-kondo/cljfmt

* transforms in read_resource tool

* get-dashboard-details

* test fixes

* fix temporal checks

* fix field_stats test

* fix remove-unreadable-transforms

* oh yeah very important type

* fix usage in native streaming

* fix api test formatting

* Get tools back (#69901)

* drop separate url for native agent, only have single url with a toggle

* fix error message in custom-elements e2e

* prompt generation (#69970)

* feat: documents content generation for clojure metabot (#69807)

* llm model select (#70061)

* BOT-866 Add prometheus metrics to metabot clojure agent part II (#70094)

* BOT-866 Add prometheus metrics to metabot clojure agent

* BOT-866 Also count inline aisdk errors

* BOT-866 push prometheus token counting down into call-llm

This is more in keeping with how current ai-service reports the metric, i.e. per llm call rather than a single batched
token usage per agent request.

This also has the advantage of keeping most prometheus metrics localized to the llm layer.

* Ensure that :metabase-metabot/llm-requests counts retries

This is more consistent with the existing ai-service llm_invocations_total metric

* Make :metabase-metabot/llm-duration-ms per llm invocation rather than cumulative

This more closely matches the existing ai-service llm_duration_ms metric

* Add :metabase-metabot/agent-duration-ms prometheus metric

Records the full duration of the outer agent loop, now that :metabase-metabot/llm-duration-ms records individual llm calls.

* Add comment on :metabase-metabot/llm-duration-ms buckets

And extend the low end of the range down to 100ms

* fixup! Add :metabase-metabot/agent-duration-ms prometheus metric

* Fix whitespace

* Add prometheus metrics tracking to call-llm-structured

* Allow llm callers to specificy the source label for prometheus metrics

And pass "example-question-generation" for question generation.

* Fix call-llm-prometheus-test

After rebasing on #70061 these tests need to include the "openrouter/" provider prefix along with the model.

* BOT-1051 Fix provider in generate-example-questions (#70121)

After #70061 call-llm-structured now expects the model to include a
provider prefix, so "anthropic/claude-haiku-4-5" was getting parsed as
:provider "anthropic" :model "claude-haiku-4-5".

Update metabase-enterprise.metabot-v3.example-question-generator/call-llm to
use the provider + model configured via llm/ee-ai-metabot-provider

* BOT-1039 Add snowplow token_usage event tracking to the clojure agent (#70049)

* BOT-1039 Include the profile :name in the profile map in register-profile!

Sometimes it's useful to be able to exract the profile name when you only
have a reference to the profile.

* Add token_usage snowplow event tracking to the clojure agent

- refactor register-profile! to single-arg form with :name now stored in the profile map and returned by get-profile
- report-token-usage-xf now emits a :snowplow/token_usage event per LLM call alongside existing prometheus metrics
- pass tracking-opts from loop-step through call-llm into the token-usage transducer
- likewise for callers of call-llm-structured
- init-agent generates a per-run request-id UUID
- run-agent-loop accepts an optional conversation-id that turns into the snowplow token_usage session_id

* Add :model to tracking-opts and drop separate source arg

The prometheus source label should always be the same as the snowplow :tag (that's how it works in ai-service), so
drop the separate `source` arg from various functions and just take the source label from the tracking-opts :tag.

* Destructure token-opts in report-token-usage-xf

* Allow passing tracking-opts to run-agent-loop

And use this to override the :source in metabot-v3.api.document/native-generate-content

* Improve docstring for tracking-opts

* Provide model and source defaults in report-aisdk-errors-xf

* Fallback to analytics-uuid if premium-embedding-token is unset

* Fix typo: snowplot -> snowplow

* Compute hashed-token-or-uuid once rather than for each usage part in report-token-usage-xf

* BOT-1039 Move token-usage funcs into analytics module (#70213)

* BOT-1052 Move token-usage funcs into analytics module

So they can be shared between oss sql gen and metabot.

* Add some snowplot tests for self/call-llm and call-llm-structured

* Add prometheus tests for call-llm-structured

* Add basic snowplow and prometheus tests for example question generation

* Modify agent loop snowplot test to use with-fake-snowplow-collector

* Modify native-generate-content-snowplow-test to use with-fake-snowplow-collector

* Fix whitespace

* fix: context not included in sql profile

* drop unused tool find-outliers (#70424)

* fix: add error field to transforms

* fix: common library not used by agent

* BOT-1053 Add snowplow events for agent tool calls (#70338)

* BOT-1039 Create metabase.analytics.util

And move some func there from metabase.analytics.llm-token-usage that will also be needed for agent_used_tool events.

* Add ai_service_event snowplow schema

In preparation for tracking the following events:

- agent_tool_used
- user_intent
- agent_action_summary

* Track snowplow agent_used_tool events in metabase-enterprise.metabot-v3.self/call-llm

- add agent loop :iteration to tracking-opts
- add :duration-ms to :tool-output parts
- add report-tool-usage-xf to transducer chain in metabase-enterprise.metabot-v3.self/call-llm to track
  :snowplow/ai_service_event with :event "agent_used_tool"

* BOT-1054 Add snowplow events for user intent classification (#70351)

* BOT-1054 Add snowplow events for user intent classification

* Move run-agent-loop :conversation-id into :tracking-opts :session-id

It does make some sense as a top-level argument, but it's currently only used for snowplow tracking, so push it down
into the tracking-opts.

* Move run-agent-loop :track-user-intent? into :tracking-opts

* Add ee-ai-metabot-provider-lite defsetting and use it in classify-user-intent!

This allows using a lighter weight model for simple tasks like user intent and/or agent response
classification. Defaults to openrouter/openai/gpt-oss-20b which is the same model used by ai-service for these tasks.

* Add run-agent-loop! test helper to run the agent for side effects

* whitespace: fix alignment

* Extract :tracking-opts schema into an mr/def similar to other agent opts

* Rename :profile-name -> :profile-id in tracking-opts

* use embeddings proxy directly rather than via ai-service (#70419)

* fix modules config

* fix: metabot has no context on the currently open transform (#70506)

* sql profile requires tool call to be forced (#70497)

* fix snowplow test

* revert back renames for ai-service embedding provider to evade migration (#70649)

* Add ai-service-port to branches list in uberjar.yml

* BOT-1085 Allow user-intent classification to be disabled (#70521)

Add a new ee-ai-metabot-internal-tasks-enabled? setting to allow disabling metabot internal "bookkeeping" tasks that might make additional llm calls, like user intent classification.

* Fix incorrect docstrings and copy-paste errors in settings and tools (#70793)

* Ai service port  validate sql (#70259)

* metabot-v3.tools.util/validate-sql stub

* Add query to dialect mapping

* Hook validation into tools code

* Add validation error instruction

* query-by-id helper

* Move sql validation to agent/tools/sql.clj

* WIP convert edit-sql-query-tool

* Revert edit-sql-query tool

* Drop validation code from tools/util.clj

* Add tools/sql_validation.clj

* Use sql-validation in tools/create_sql_query.clj

* Use sql-validation in agent.tools.sql/create-sql-query-tool

* Add transpile_sql to sql_tools.py

* Add transpile-sql to sql-parsing

* Macaw implementation stub

* Add transpile-sql interface multimethod

* Update transpile_sql in sql_tools.py

* sql-tools/transpile-sql stub

* Add template tag sentinel to sql_tools.py

* sql-tools/transpile-sql schema

* Sqlglot transpile-sql wrapper

* sql-parsing/transpile-sql result normalization

* Hook sql-tools/transpile-sql into metabot-v3.tools.sql-validation/validate-sql

* Adjust create-sql-query-tool to validate-sql changes

* Adjust reason in sql_tools.py

* Add create-sql-query-validation-failure-test

* Addjust validate-sql

* Revert edit-sql-query tool

* Add validation to metabot_v3/tools/edit_sql_query.clj

* Add schema and update returns for create-sql-query

* Add metabot-v3.tools.sql.common

* Update edit_sql_query

* Update edit_sql_query tool

* Add validation failure test for edit-sql-query-tool

* Adjust edit-sql-query-code-edit-tool

* Adjust create-sql-query-code-edit-tool

* Update replace-sql-query and related

* Adjust replace-sql-query-tool

* Update replace-sql-query-code-edit-tool

* Adjsutment for test

* metabot-v3.tools.sql.validation ns

* validate-sql sentinels

* Hoist template tags sentinel into tools.sql.validation

* Update schema

* Validation tests

* Add transpilation tests and adjust sql_tools.py

* Add dialect mapping

* Adjust validation and tests

* Adjust test

* linter

* Cleanup

* Add tests

* Tests and validation

* More tests and cleanup

* Drop redundant tests

* Use original dialect

* Adjust tests

* whitespace

* Remove direct query manipulation from tests

* Remove direct mbql manipulation from create-sql-query

* Remove more of direct query manipulation

* More remarks

* surface openrouter error messages

* API keys are sensitive (#70847)

* Generate tool manifest from endpoint metadata (#70780)

* Generate tool manifest from endpoint metadta

* Delete reference file

* tweak-and-tidy

* More testing, more robustness

* Fix kondo and cljfmt

* Scrap name inference

* Clean up tool assertions

* Remove silly separators

* Switch away from tool registry approach

* rename + slightly simplify prefer-tool-descriptions

* Replace definitions binding with an explicitly threaded atom

* Minor cleanups/refactor

* Pull over some annotations from my prior PR; tweak test comments

* address comments

---------

Co-authored-by: Noah Moss <noahbmoss@gmail.com>

* properly fetch data for user-is-viewing context (#70857)

* serialize error to string if it is not - backend expects a string anyways

* chore: trigger CI

* [BOT-1056] Metabot Analyze Chart in CLJ Port (#70177)

* init analyze chart tool

* fix compilation error; add interpretation instructions; reduce memory leak

* Add license overrides for techascent/tech.config and net.openhft/zero-allocation-hashing

* Remove hard-coded :debug true in /agent-streaming endpoint

* Fix conflict resolution due to tools.analytics after rebase

tools.analytics and find-outliers were dropped in 974b595784

* BOT-1058 analyze chart add support for non timeseries charts (#70616)

* Add stats for categorical charts to analyze-chart tool

* Add stats for scatter plots to analyze-chart tool

* Add stats for histograms to analyze-chart tool

* Add time series tests for metabot chart analytics

* Add outliers tests for metabot chart analytics

* Small tweaks to reduce the diff between clojure port an ai-service stats

stats/scatter.clj

- Added sample-points helper (random sample up to 30 pairs)
- compute-series-stats: adds :sampled_points (30 random [x y] pairs),
  :outliers (MAD-based, x-values passed as "dates" so each outlier carries its x-coordinate in :date)
- compute-scatter-stats: extracts :x_name / :y_name from series metadata

stats/categorical.clj

- compute-categorical-stats: extracts :x_name / :y_name from series metadata

stats/histogram.clj

- compute-series-stats: now takes optional x-values (single-arity falls back to sequential indices);
  adds :bin_data (all [x y] pairs)
- compute-histogram-stats: extracts :x_name / :y_name from series metadata

stats/repr.clj

- generate-temporal-context: added "incomplete period" sentence
- New compute-data-characteristics: derives small_counts/high_variance/sparse_data flags from existing stats fields (no raw values needed)
- New render-data-characteristics-note: emits **Note**: ... matching Python's exact warning text
- All generate-*-representation functions: use display-type from context for the **Type**: line (fixes "Scatter" → "bar" for binned bar charts)
- Scatter: added **X-axis**, **Y-axis**, note, **Sample Data**, **Outliers** (x=..., y=...) sections
- Categorical: added **X-axis**, **Y-axis**, note
- Histogram: added **X-axis**, **Y-axis**, note, **Bin Data** section (in addition to existing percentile/shape stats)

* Add Data Points to categorical repr to match python implementation

* Do not mention cross-referencing the chart visual

Unlike the Python implementation, the clojure port does not include the chart image in the context.

* Fix detect-chart-type to correctly detect histograms

histograms have :display_type "bar" not "histogram"

* Add some limits on amount of data to analyze in analyze_charts

Downsample series data to 10k datapoints and cap series at 10 when calculating cross-series correlations.

* Add metabot-v3.stats.util ns and move some shared code there

* Use TMD funcs to compute percentiles, quartiles, skew and kurtosis in histogram.clj

* Cleanup comments and formatting in stats/core.clj

* Cleanup comments and formatting in stats/categorical.clj

* Cleanup comments and formatting in stats/histogram.clj

* Cleanup comments and formatting in stats/repr.clj

* Cleanup comments and formatting in stats/scatter.clj

* Fix make-series and drop compute-summary-median-test in util_test.clj

* Cleanup stats tests

* Use =?/approx in test assertions where appropriate

* Move all repr tests into repr_test.clj

* Add some more repr tests

* Add ^:parallel to metabot stats tests

* Make defs private where possible

* Add malli schemas for public funcs in metabot stats

* Replace some? with more specific test assertions where appropriate

* Remove unused find-outlier-indices

* Remove unused malli schemas ::analyze-chart-input ::analyze-chart-output ::chart-type

* Move nan->nil into stats.util and use it in compute-series-stats

* Rename `dates` arg to `labels` in find-outliers and find-outliers-cumulative

These funcs were originally added for timeseries data where the dependent variable was a date/time value, but are now
used for other chart types were the dimension might be any value.

* Fix trailing whitespace

* Convert series keys to strings in chart configs

* Change ::column-type malli enum from keywords to strings

This matches what we get from the frontend

* Add X-axis range to histogram stats and rename **Bin Data** to **Sample Data**

To match the scatter plot output

* Reduce code dup and extract shared helpers in repr.clj

* Fix kondo warning: reduce -> apply

* Add missing keys to malli schemas

* Ensure top/bottom categories are also deduped and aggregated

* Only calculate categorical :percentage if all values are non-negative

* Handle case where correlation coefficient is exactly zero when setting :direction

* Record :data_points in addtion to :categor_count for categorical stats

* Switch to computing weighted estimates plus structural metrics for binned histogram data

* Fix lint error due to reflection warning

* Fix waterfall chart type detection and improve handling for :unknown charts

Co-authored-by: Oleksandr Solovyov <o@solovyov.net>
Co-authored-by: Maksym Yakubych <undrfined@gmail.com>
Co-authored-by: Mike Appleby <86076+appleby@users.noreply.github.com>
Co-authored-by: Maksym Yakubych <maksym@metabase.com>
Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
Co-authored-by: Noah Moss <noahbmoss@gmail.com>
Co-authored-by: Tyler Plude <tsplude@gmail.com>
2026-03-17 16:22:57 +02:00
Nemanja Glumac
65309ff9cb Revert "Update translations 2026-03-11 (#70712)" (#71003)
This reverts commit a989194135.
2026-03-17 14:26:08 +01:00
Nemanja Glumac
36be55e774 Increase the polling timeout (#70999) 2026-03-17 14:00:30 +01:00
Riley Thompson
0c0f3450dd Show expected type in custom expression error message (#70400)
* initial attempt at better error message

* clean up

* Clean up

* improve doc string

* fix cljc test

* add test

* fix test

* exclude perf functions

* have schema produce user facing expected type

* clean up

* Add test

* fix kondo

* defer i18n

* try test fix

* address comments

* update tests
2026-03-17 08:54:48 -04:00
github-automation-metabase
5ac9afd0f5 Auto-update documentation for master (#70988)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-17 08:52:37 -04:00
Jakub Chodorowicz
21ebfb0a1b Gdgt 2002 transform inspector shows 12 matched columns but renders 2 (#70951)
* create failing test case for comparison layout and groups

* fix cards not loading when they part of group is visible
2026-03-17 13:48:32 +01:00
Uladzimir Havenchyk
52d5e78767 fix: perf improvements for documents (#70802)
* fix: perf improvements for documents

* fix unit test

* address comments
2026-03-17 13:40:47 +03:00
Kamil Mielnik
492008d7fd GDGT-1939 Get rid of VisualizationSettingDefinition["props"] (#70867) 2026-03-17 14:12:56 +07:00
Rodrigo López Dato
08c8928cf3 Update Athena parameter suggestions to JDBC v3 driver (#62689) 2026-03-16 17:16:14 -06:00
github-automation-metabase
a989194135 Update translations 2026-03-11 (#70712)
* Update translation sources 2026-03-11

* Update translations

* Fix host/sample apps e2e assertions

* Improve assertion

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Nemanja <31325167+nemanjaglumac@users.noreply.github.com>
2026-03-16 17:15:56 -06:00
Braden Shepherdson
3c152db0a1 [MBQL lib] Start on user docs: top-level and expressions (#70375)
Part of QUE2-366.
2026-03-16 17:15:33 -06:00
Nathan Voxland
19d6d374c8 Correctly detect funnel chart config in static-viz (#68158) 2026-03-16 15:43:29 -05:00
Kevin Kelleher
7e3b3f1818 Fix trend visualizations that rely on aggregated datetimes (#70941) 2026-03-16 14:37:45 -04:00
Kevin Kelleher
4cb40dd358 Fix sunburst chart labels not appearing (#70889) 2026-03-16 14:37:25 -04:00
Nicola Mometto
525b09b87b incremental transforms with source filter (#70573)
* WIP: incremental transforms with source filter

* fix: route through substitution

* chore: remove useless check, we're already in python specific code

* fix: validate before parsing

* style

* fix test

* chore: format

* chore: turn off legacy incremental settings

* chore: remove dead code

* chore: remove dead code

* fix tests

* fix warnings

* fix

* update modules

* feat: store actual type

* feat: derive type, store lo/hi in transform runs

* feat: store checkpoint early so it's available on afailure

* feat: surface checkpoint values in UI

* refetch after run

* surface checkpoint value in UI

* fixes for the linter gods

* chore: format

* remove dead e2e test

* fix rebase

* feat: reset checkpoint if incremental field changes

* chore: do it in before-update instead

* chore: test

* chore: add preconds

* fix: remove rebase field that got in

* feat: thread source-range-params through

* fix test

* remove secondary index

* chore: proper schema

* fix: extract proper source columns from UI components

* fix e2e test

* add option to reset checkpoint

* UI: confirmation on field change

* style

* don't break on old import

* fail when running an incremental transform w/o a field set

* chore: polish UI

* appease linter

* add source-filters to table template tags in the BE

* chore: test

* chore: restrict ops

* extend schema

* chore: extract ->sql util

* chore

* some BE cleanup

* make checkpointFilterFieldId mandatory

* preselect first checkpointFilterFieldId when selecting incremental in standalone variant

* improve forced type assertion

* autoselect first value for checkpoint field also in embedded mode

* extract useAutoSelectFirstOption hook

* refactor nested ternary

* disable incremental toggle when no fields checkpoint available

* add better warning for native query lack of tag

* allow turning off incremental for transforms with issues

* consolidate temporal value to ISO

* Adjust style of reset checkpoint button

* Adjust modal confirmation copy

* convert date to iso also in  save-watermark

* fix date time field type detection

* remove superflous space

* feat: better mbql migration

* fix: whitespaces

* extend FormInlineUpdated to accept break condition onBeforeUpdate

* adjust styling

* extract ResetCheckpointSection

* remove superfluous comment

* rename hooks file

* refactor hasCheckpointOptions

* add comment about stage

* chore: validation

* CTA warning on malformed transforms

fix

* fix: refer to variable instead of template tag

* chore: i18n

* refactor transform warning

* schemas for source-range-params

* deal with review comments

* feat: emit via honeysql instead of string interpolation

* fix: use lib/template-tags

* cleanup

* fix IncrementalTransformSettings tests

* refactor, extract TransformType type

* fix: indent

* fix check

* fix tests

* fix lint

* simplify useHasCheckpointOptions

* cleanup utils unit tests

* chore: also add to lib/schema

* fix missing query metadata in useHasCheckpointOptions

* reset the checkpointFilterFieldId if incremental switch is toggled of

* fix transforms e2e tests

* feat: migration test

* chore: reorder

* adjust transform create tracking

* fix e2e GDGT-1774 reproduction

* fix missing space

* simplify useAutoSelectFirstOption hook

* add incremental sql transform e2e test

* add native sql incremental transform test

* add python incremental transform e2e test

* skip sql test for now

* auto include aliases

* simplify hover info

* fix and unskip incremental schema test

---------

Co-authored-by: Dan Stone <wotbrew@gmail.com>
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2026-03-16 17:20:46 +00:00
Riley Thompson
0ac98129d9 Inline parameter in clickhouse honeysql method (#70905)
* suggested fix and test

* Clean up test

* clean up test
2026-03-16 15:49:00 +00:00
Nicolò Pretto
64712e1f3f feat(embed-onboarding): Block all schemas that does not contain selected (#70717)
* feat(embed-onboarding): Block all schemas that does not contain selected
tables when setting up RLS

* v2

* fix e2e

* clean up tests
2026-03-16 16:16:45 +01:00
Eric Normand
f3bff3f028 Fix 500 error in check-card endpoint for cards with broken dependents (#70828)
Fix unhandled exception in POST /api/ee/dependencies/check-card that causes a 500 when a transitive dependent card fails to compile

 When check-query-soundness iterates over all dependents, if any card's query throws during compilation (e.g. alias resolution errors), the exception propagated uncaught and crashed the entire endpoint
 
Added try/catch around check-entity calls in check-query-soundness, returning a validation-exception-error instead of crashing — consistent with the pattern already used in `/dependencies/findings.clj`

On the stats instance, card 4523 has 2,557 transitive card dependents. One of those dependents (a native query referencing card 34523 via a template tag) fails during query compilation with `Missing ::desired-alias->escaped for "email_domain"`. This compilation error is unrelated to the proposed edit but was bringing down the whole endpoint.

Test plan

  - Verify POST /api/ee/dependencies/check-card returns 200 with {success: false, bad_cards: [...]} instead of 500 when a dependent card has a query compilation error
  - Verify that cards with compilation errors appear in the response as validation-exception-error findings
  - Existing dependency check tests still pass
2026-03-16 14:59:17 +00:00
Ngoc Khuat
8454245aaa Use safe identifier quoting in workspace grant statements (#70869) 2026-03-16 14:58:24 +00:00
Nicola Mometto
3cc709ee43 Aliases for table template tags (#70893)
* auto include aliases

* simplify hover info

* add unit test for emit tables toggle

---------

Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2026-03-16 14:56:21 +00:00
Nicola Mometto
88729c52f1 Table tags filters (#70699)
* add source-filters to table template tags in the BE

* chore: test

* chore: restrict ops

* extend schema

* chore: extract ->sql util

* deal with review comments

* feat: emit via honeysql instead of string interpolation

* fix check

* chore: also add to lib/schema
2026-03-16 13:56:47 +00:00
Nicola Mometto
d8104c911d untgz: use resolveIn to prevent zip slip (#70921) 2026-03-16 12:49:46 +00:00
Nicola Mometto
5d5930ab64 Track OSS transform usage in Snowplow (#70925)
move snowplow transform metrics to OSS, as transforms are now available on OSS
2026-03-16 12:47:28 +00:00
github-automation-metabase
2738ec81b7 Reduce number of tests kept in memory for embedding SDK component tests (#70928)
* Add memory management settings to SDK component test Cypress config

Add experimentalMemoryManagement: true and numTestsKeptInMemory: 0 to
the embedding SDK component test config. The config spreads defaultConfig
which lacks these settings, causing Cypress to retain 50 DOM snapshots
per test (the default). This leads to Chrome renderer OOM crashes during
content-translations.cy.spec.tsx.

- experimentalMemoryManagement: true triggers gc() between tests
- numTestsKeptInMemory: 0 prevents DOM snapshot heap accumulation

* Use numTestsKeptInMemory: 1 to match main CI config convention

Change from 0 to 1 per review feedback. This matches the value used in
the main e2e config (config.js:190) and keeps the last snapshot available
for debugging while still preventing OOM from the default of 50.
2026-03-16 12:35:32 +00:00
Nicola Mometto
cd77eb5140 Skip running transform jobs if there are no transforms to run (#70926)
* fix: don't run transform jobs if there are no tranforms to run

* chore: add test
2026-03-16 12:34:46 +00:00
Kevin Kelleher
2a4046736a Fix pivot table drill through when binning a datetime by day (#70680) 2026-03-16 07:29:47 -04:00
Ngoc Khuat
660c1ddfe6 Fix flaky scoring-test/mine-test on H2 (#70852) 2026-03-16 17:48:53 +07:00
Ngoc Khuat
6845e78a5d Fix flaky schema-change integration test on Redshift (#70863)
Fix flaky python-transform-schema-change-integration-test on Redshift

Replace fixed Thread/sleep with polling for correct field metadata.
The transform pipeline sets run status to :succeeded before
complete-execution! (which runs the metadata sync) finishes. On
Redshift, the sync takes longer due to network latency, so the
2-second sleep was insufficient — the QP would query with stale
Field records (still referencing the old "age" column).
2026-03-16 17:48:27 +07:00
github-automation-metabase
eea9a750d6 Add 403 error handling to rerun-workflows.yml (#70916)
Handle 403 errors in rerun-workflows.yml

Wrap the reRunWorkflowFailedJobs API call in a try/catch that
gracefully handles HTTP 403 errors. This prevents false-positive CI
failures when the target run is cancelled, a PR run, or otherwise
ineligible for retry.

Also adds missing await to the API call so errors are properly caught.
2026-03-16 08:42:34 +01:00
metabase-bot[bot]
123a4f966d [chore] Update E2E test timings with recent data (#70913)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-03-16 07:02:38 +01:00
Denis Berezin
659d0a37b1 Add side-panel to Tables and Metrics in the Library (#69673)
* Temp

* Add full implementation

* Add e2e tests

* Remove excess image file

* Temp

* Address design issues

* Fix design review comments

* One more fix

* Fix e2e tests

* Remove empty source gotcha

* Address review issues

* Revert graphy changes
2026-03-14 02:22:45 +03:00
Eric Normand
59a52b2631 Validate FK target and dimension remap fields belong to the same database (#70879)
- Adds same-database validation for `fk_target_field_id` in `PUT /api/field/:id` (resolves existing TODO)
- Adds existence and same-database validation for `human_readable_field_id` in `POST /api/field/:id/dimension`
- Returns 400 if the target field belongs to a different database than the source field
2026-03-13 22:22:20 +00:00
bryan
a83196324b Fix MySQL 8.4 app-db test failures in dependencies tests (#70897) 2026-03-13 16:11:42 -06:00
Robert Kosara
9ab2bfbae8 Update HAR file creation instructions to include sensitive data (#70394)
Updated the documentation to clarify that the HAR file contains sensitive data and revised the instructions for saving the HAR file accordingly. Also added a screenshot of the settings in Chrome.

---------

Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
2026-03-13 14:28:16 -07:00
Eric Normand
c261122999 Fix broken deps not surfaced for missing fields in :fields (GHY-3157) (#70865)
- The `:soft?` marking in `find-bad-refs-with-source` was too broad — it marked **all** bad refs in `:fields` clauses as soft, even when the field was completely missing from the source (not just inactive).
- Added `(not (:active column true))` guard so only **inactive** fields in `:fields` are marked `:soft?`. Missing/unresolvable fields remain hard errors and are properly surfaced by dependency analysis.
- This preserves the GHY-3044 fix (inactive fields the QP can drop are still soft) while fixing GHY-3157 (genuinely missing fields are reported).
2026-03-13 21:03:54 +00:00
Denis Berezin
0b65ccce3a UXW-3177 batch dashcard queries by 5 (#70542)
* UXW-3177 batch dashcard queries by 5

* Add unit tests

* Remove fetch limit for HTTP2+
2026-03-13 23:44:45 +03:00
Nathan Voxland
bb2adc5f46 Changed repro-bot label to ".Run Repro Bot" (#70890) 2026-03-13 15:37:09 -05:00
Ben Grabow
c5dcdc3238 Temporarily disable app db version checks (#70884)
* Temporarily disable app db version checks

* Comment out unused code

* Entirely rip out unused code
2026-03-13 12:47:04 -07:00
Aleksandr Lesnenko
5537f0f258 Add cypress claude setup (#70715)
e2e skills
2026-03-13 15:06:50 -04:00
Riley Thompson
bfdd8a0b23 Handle clickhouse dbname when it has spaces in it (#70822)
* take first name

* Add test

* fix test

* Add comment

* fix typos

Fix typo in comment regarding legacy `dbname` handling.
2026-03-13 18:47:35 +00:00
Riley Thompson
3c05a30b8e Enable old clickhouse tests (#70756)
* enable clickhouse tests

* enable more tests

* fix kondo and test
2026-03-13 18:22:20 +00:00
Alex Yarosh
106a707fcc docs: it's writable not writeable (#70877)
* it's writable

* no md in redirect dummy
2026-03-13 14:14:52 -04:00
Nathan Voxland
21c8136e7e Repro Bot Enabling (#70823) 2026-03-13 13:10:22 -05:00
Nathan Voxland
d1252c7e8e Fixed merges from master 2026-03-13 11:59:15 -05:00
John Swanson
7319599ceb Fix token check errors on startup (#70789)
During startup, the database isn't migrated yet, so we can't check the
token hash.

If the database hasn't been started yet, skip checking the token hash in
the DB and just delegate to the lower-level checker that actually hits
the store.
2026-03-13 08:46:20 -08:00
Nathan Voxland
13bc693357 Can't use regex filter with \b on non-ascii names (#70838) 2026-03-13 11:36:45 -05:00
Nick Fitzpatrick
2b11a3bed2 Update react-grid-layout and react-resizeable (#70760)
* Update react-grid-layout and react-resizeable

* adding e2e test

* e2e adjustment
2026-03-13 13:20:12 -03:00
Nathan Voxland
4a7059cac7 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	resources/migrations/059_update_migrations.yaml
#	src/metabase/search/appdb/core.clj
#	src/metabase/search/core.clj
#	src/metabase/search/impl.clj
#	src/metabase/search/ingestion.clj
#	src/metabase/search/task/search_index.clj
2026-03-13 11:09:28 -05:00
Nick Fitzpatrick
c910ca3fd3 measure table names in tree in v1 data model page (#70657) 2026-03-13 12:23:45 -03:00
bryan
d8b40292d1 Disable blocking dependency checks on save (#70819) 2026-03-13 15:18:49 +00:00
Nick Fitzpatrick
b773f68f23 update html2canvas-pro (#70728)
* update html2canvas

* Update Loki Snapshots

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-03-13 12:13:20 -03:00
Edward Paget
647861b624 test: agent-specific test runner (#70821)
* test: agent-specific test runner

Adds an "agent" test runner that filters the output of running `clojure
-X:...:test` commands to make it more relevant for agents preventing
them from needing to use tail or grep to find information and reducing
context pollution.

Also implements randomized ports for test web-servers allowing multiple
agents to run tests in parallel (or to run multiple commands in
parallel). This removes the directive to use the ./bin/mage-based test
runner, to direct agents to use the agent-specific runner.

* fixup! missing import

* add the test agent script
2026-03-13 10:00:49 -05:00
lbrdnk
e741639713 Error source for native entities (#70021)
* Update schema with unknown error source

* Adjust validate-native-query

* Update tests

* Extend error source to multi table queries

* Update test

* Sql-tools providing more functions

* Card references

* Update tests

* require

* Unrelated fix

* repl reloading

* Tests

* Use placeholders instead of dummy subqueries

* Comment

* Placeholders

* Modules (temporary)

* potemkin

* Address circular deps extend sql-tools interface

* Sort modules

* Fix params

* Adjust test

* Placeholder

* More tests

* Cleanup

* whitespace

* Remove explicit unknown for now

* typo

* Update tests

* Break the circular dep more standard way

* Add comment

* whitespace
2026-03-13 16:00:06 +01:00
Anton Kostenko
5765b0df15 Add OpenTelemetry Tracing module (#69295)
* Add OpenTelemetry Tracing module

---------

Co-authored-by: dan sutton <dan@dpsutton.com>
Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2026-03-13 10:48:13 -04:00
Nicola Mometto
40d00b8e7f add missing tags to enterprise settings (#70846)
fix: add missing tags to enterprise settings
2026-03-13 13:07:48 +00:00
github-automation-metabase
58cde65c4e Auto-update documentation for master (#70840)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-13 09:05:50 -04:00
Sébastien
5995621da8 Fixed color flickering for sdk question titles (#70842) 2026-03-13 13:52:48 +01:00
Sébastien
70d4a78914 Fixed issue when hiding SDK banner (#70727) 2026-03-13 13:52:30 +01:00
Fraser
cf6e1c032a Add module metrics (#70841) 2026-03-13 06:49:54 -06:00
Riley Thompson
e70f22e0eb Upgrade snowflake jdbc to 4.0.1 (#70505)
* upgrade snowflake jdbc to 4.0.1

* remove unnecessary exclusions

* replace internal parse

* fix eastwood

* address comments

* handle edge case
2026-03-13 08:43:15 -04:00
Riley Thompson
4fd189509f Ignore unknown settings in clickhouse (#70799)
* move additional options to clickhouse settings

* add test

* add test description

* add prefix and keep in subname

* just ignore unknown settings

* fix test
2026-03-13 12:39:37 +00:00
Ngoc Khuat
f7fd7fe5c5 Add workflow_dispatch action to reset cloud datasets (#70744) 2026-03-13 19:06:30 +07:00
Nicolò Pretto
a0e28bc775 fix: use the correct setting for enabling metabot in the embed wizard (#70820) 2026-03-13 09:54:13 +01:00
Aleksandr Lesnenko
a5b4f10c10 Metrics viewer fixes (#70655)
* fix conflicting filters on the same dimension

* og pr review feedback

* fix label
2026-03-12 22:54:34 +00:00
bryan
57502d5ef1 Fix cloud driver tests skipped when deps.edn changes [DEV-1672] (#70833) 2026-03-12 15:24:41 -07:00
bryan
b2f981e967 Fix flaky sync-materialized-views-test with auto-retry (#70750) 2026-03-12 15:50:48 -06:00
Fraser
fb8f72b7bd Setup boundaries linter (#70768) 2026-03-13 10:14:20 +13:00
Riley Thompson
502b66528c Wrap sqlserver boolean expressions in a case statement (#67136)
* wrap in case

* wrap case in cast, cleanup

* comments

* rename

* add test

* move comparison operators to lib.schema.filter

* Add boolean ops

* add and, or, not. rename comparison to predicate

* clean up tests
2026-03-12 17:05:01 -04:00
Jeff Bruemmer
2838b6501c docs - clickhouse server setting prefix (#70827)
clickhouse server setting prefix
2026-03-12 14:01:06 -07:00
Nemanja Glumac
7603550836 Revert "Replace circleci Docker images with the official DB images (#70773) (#70813)
This reverts commit 9ad40ab1c3.
2026-03-12 20:56:55 +01:00
Nick Fitzpatrick
ba8074bb87 New password generation for users (#70646)
* New password generation for users

* update to use window.crypto
2026-03-12 16:31:12 -03:00
John Swanson
90097715d2 dev env + start (mage -johnswanson-dev-env) (#70741)
Babashka task that starts up an isolated dev environment per worktree. Expands on @edpaget's excellent work, with interactive fzf prompts for edition, token, appdb, and warehouse services. Optional `--run` flag to launch backend + frontend in the background with PID tracking. Persistent config in `.dev-env-state.edn` for reuse across invocations.
2026-03-12 08:58:06 -08:00
Stas Gavrylov
12839276af GDGT-1893: Generate .d.css files to support CSS Variables autocomplete (#68723)
* CssVarsDeclarationPlugin: Add plugin and documentation to generate .d.css files at build step

* CssVarsDeclarationPlugin: Add recommended .vscode settings to support CSS vars autocomplete

* CssVarsDeclarationPlugin: Fix nested unions parsing

* CssVarsDeclarationPlugin: Add unit tests

* Update vscode settings for css vars to include Mantine
2026-03-12 18:24:54 +02:00
Nemanja Glumac
2ef536a0fe Cross-version follow up (#70800)
See:
https://github.com/metabase/metabase/pull/70063#discussion_r2924663893
2026-03-12 16:53:57 +01:00
Nemanja Glumac
9ad40ab1c3 Replace circleci Docker images with the official DB images (#70773) 2026-03-12 15:21:32 +01:00
Mahatthana (Kelvin) Nomsawadi
6351e5bc0e Fix SDK subscription not working under StrictMode (#70663)
* Fix can't click on the time dropdown on subscription sidebar in StrictMode

* Add tests

* update e2e test

* Fix unit tests

* improve code clarity

* Fix E2E tests

* Simplify code

* Make default value consistent

* Make the new Select button have dynamic size

* Fix unit tests

* Fix E2E tests
2026-03-12 14:09:28 +00:00
Nemanja Glumac
18d8dadf1b Cross-version testing infrastructure - Stage 1 (#70063)
Adds health-check-only cross-version migration tests using Docker Compose
with PostgreSQL. Tests verify that Metabase can upgrade/downgrade between
versions by checking the `/api/health` endpoint.

Usage:
```
./cross-version/test.sh --source v1.58.6 --target v1.58.7
```

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-12 14:36:47 +01:00
Chris Truter
d5f606e8f2 Upgrade toucan2 to 1.0.571 (#70771) 2026-03-12 14:00:09 +01:00
Alex Yarosh
acbf476d8b docs: maybe not deprecating (#70790)
Revise guidance on using Transforms over models

Updated recommendation for using Transforms instead of models.
2026-03-12 08:56:37 -04:00
Nick Fitzpatrick
21af2827f2 homepage redirect in useLayoutEffect (#70658) 2026-03-12 09:22:45 -03:00
Mahatthana (Kelvin) Nomsawadi
04b141b975 Fix flakes because we used JS instead of CSS (#70718) 2026-03-12 12:09:36 +00:00
Sébastien
ff9d9acdac Embedding upsells now open data studio modal in cloud (#70565) 2026-03-12 12:47:49 +01:00
Nemanja Glumac
d7848ee998 Bump eastwood timeout to 30 minutes (#70770) 2026-03-12 11:31:06 +01:00
Chris Truter
47c037a3f8 Use lib for MBQL construction in Workspace tests (#70532) 2026-03-12 09:38:01 +00:00
Chris Truter
ab1ccbf8ec Forward port migration moves from 58 -> 59 (#70765) 2026-03-12 09:30:07 +00:00
Chris Truter
8662aaaa87 Re-enable schema that was giving trouble (#70708) 2026-03-12 08:27:07 +00:00
Chris Truter
81b10ad959 Delete changesets orphaned by move from 59 -> 60 (#70719) 2026-03-12 08:25:10 +00:00
bryan
0a67d24d79 Fix dataset-already-loaded?-test flake on Redshift (#70748) 2026-03-11 16:20:36 -06:00
Romeo Van Snick
258305b914 Fix flakes (#70296)
* Fix flake

* Wait for unreferenced entities

* Wait for unreferenced entities

* Fix helper

* Fix test
2026-03-12 08:58:46 +11:00
Ben Grabow
21b67b2892 Show read-only mode banner to all users (#70529) 2026-03-11 16:22:01 -05:00
Nathan Voxland
3dcbfef5c5 Support MB_MONITOR_PERFORMANCE to write as files to a directory (#69582) 2026-03-11 15:41:56 -05:00
Ben Grabow
1ccf800dee Update minimum App DB versions (#70446)
* Upgrade mariadb images to 10.4.0

* Update job names to match the new version

* Advance minimum mariadb version to 10.4.6 to exclude unstable early versions of 10.4

* Don't specify patch version

* Upgrade images to MariaDB 10.6

* Upgrade CI actions to use pg14

* WIP: start updating MySQL 8.0 -> 8.4

* Advance minimum required app db versions

* Revert "Upgrade CI actions to use pg14"

This reverts commit 82f1aec823.

* Revert "WIP: start updating MySQL 8.0 -> 8.4"

This reverts commit c1c78d4298.

* Revert "Upgrade images to MariaDB 10.6"

This reverts commit f99d3c4f04.

* Revert just about all the changes to run CI

* Use newer MariaDB in semantic search tests

* Use newer mysql in semantic search tests

* Use newer postgres in semantic search tests

* Update app db version

* Update postgres version

* Trigger mysql driver tests

* Update unit tests to expect the new required versions

* Update mariadb and mysql used in drivers tests

* Fix expected supported mysql versions

* Remove dirt

* DRY the tests

* Dirt to trigger some CI tests

* Dirt to trigger some CI tests

* Remove dirt and update failing CI job

* Remove dirt

* Update another missed CI definition
2026-03-11 13:58:35 -05:00
da
d4d83d2f8e Upgrade Jetty to 12.1.7 (#70731)
CVE fix
2026-03-11 18:29:58 +00:00
Riley Thompson
3e655a0bb2 Get default port from nested connection properties (#70713)
* search for port in group fields

* add test

* update test

* simplify test

* fix sqlite
2026-03-11 18:06:17 +00:00
github-automation-metabase
0409c4a20b Add retry + checksum to Clojure install, remove continue-on-error (#70700)
* Add retry + checksum to Clojure install, remove continue-on-error

Remove continue-on-error: true from the Install Clojure CLI step so failures
surface immediately instead of silently propagating to downstream steps.

Add retry logic (3 attempts with curl --retry and --fail) and a post-install
clojure --version gate to handle transient download failures from
download.clojure.org.

* Add explicit error message when all Clojure install retries fail
2026-03-11 17:14:53 +00:00
Nicolò Pretto
b51c0c9efa fix typecheck broken on parameters.unit.spec.ts (#70725) 2026-03-11 15:53:12 +00:00
Nicola Mometto
51f8fb9af1 fix expected status of bigquery tests after #62351 (#70710) 2026-03-11 15:20:44 +00:00
metamben
bfb0b42b42 Get rid of category and id parameter types (#70196)
* Get rid of `category` and `id` parameter types

Closes QUE2-326
2026-03-11 17:40:42 +03:00
Chris Truter
09544d950d Log the migrations blocking the downgrade (#70701) 2026-03-11 13:19:18 +00:00
github-automation-metabase
03dd34ec4a Auto-update documentation for master (#70689)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-11 08:51:41 -04:00
Kamil Mielnik
d08e561420 GDGT-1793 Visualization Typescript Conversions - lib/ (#70249)
* Convert frontend/src/metabase/visualizations/lib/timeseries.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/timeseries.unit.spec.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/errors.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/mapping.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/warnings.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/trends.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/numeric.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/table.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/table.unit.spec.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/action.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/renderer_utils.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/renderer_utils.unit.spec.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/table_format.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/table_format.unit.spec.js to TypeScript
* Convert frontend/src/metabase/visualizations/lib/utils.js to TypeScript
2026-03-11 12:00:12 +00:00
mendral-app[bot]
214c38b3f2 Add retry loop to fetch-artifact action's download step (#70513)
Add retry loop to fetch-artifact download step

Wrap the downloadArtifact API call with a retry loop (3 attempts,
exponential backoff at 15s/30s) to handle transient GitHub API 500
errors that have been causing e2e and health-check job failures.

Co-authored-by: mendral-app[bot] <233154221+mendral-app[bot]@users.noreply.github.com>
2026-03-11 11:36:20 +01:00
mendral-app[bot]
52ae8a14db Fix prompt shell expansion in codespell workflow (#70290)
Fix codespell workflow: use prompt_file instead of shell expansion in YAML

The prompt field contained $(cat codespell_output.txt) which YAML passes
as a literal string — shell expansion does not occur in YAML values.
This caused Claude Code to receive the literal text instead of the actual
codespell output, resulting in exit code 1 on every nightly run.

Fix by writing the prompt to a file in a dedicated build step, then
passing it via the prompt_file input which claude-code-action supports.

Co-authored-by: mendral-app[bot] <233154221+mendral-app[bot]@users.noreply.github.com>
2026-03-11 11:23:16 +01:00
Chris Truter
e153a3290b Rename migrations that didn't make it to v59 (#70673) 2026-03-11 09:54:35 +00:00
Chris Truter
2830b3c94a Agent API for Workspaces (#70496) 2026-03-11 09:43:37 +00:00
Nicolò Pretto
2fa8abc247 Fix nested button DOM nesting in StepperWithCards (#70667) 2026-03-11 10:19:07 +01:00
Nemanja Glumac
be2a29d138 Remove devex from clj-kondo code owners (#70693) 2026-03-11 10:18:43 +01:00
Alexander Polyankin
ab089eb84d Fix CSS wrapping in replace sources (#70688) 2026-03-11 03:09:58 +00:00
Fraser
b40d76f5b4 Extract shared upsell components into common (#70619)
* Extract shared upsell components into common

 Moved to common/components/upsells/:
  - components/ subdir — the building blocks: UpsellBanner, UpsellBigCard, UpsellCta, UpsellGem, UpsellPill, UpsellWrapper, UpgradeModal, analytics, use-upsell-link
  - constants.ts — shared URLs and constants
  - 4 composed upsell pages used outside admin: UpsellEmbedHomepage, UpsellMetabaseBanner, UpsellStorage, UpsellUsageAnalytics
  - UpsellCard (merged in from its old location at common/components/UpsellCard/)

  Kept in admin/upsells/:
  - 13 admin-only upsell pages (UpsellBetterSupport, UpsellCacheConfig, UpsellCloud, UpsellDevInstances, UpsellEmailWhitelabel, UpsellHosting, UpsellPerformanceTools, UpsellPermissions, UpsellSSO, UpsellSdkLink,
  UpsellSemanticSearch, UpsellUploads, UpsellWhitelabel)
  - These now import primitives from metabase/common/components/upsells/ instead of ./components

  Updated ~30 import paths across the codebase. Reduced shared/common → feature/admin violations from 12 to 2.
2026-03-11 11:41:28 +13:00
Nathan Voxland
b12dfa4fd9 Per-PR liquibase changelogs (#70263) 2026-03-10 16:58:26 -05:00
John Swanson
5e2e510811 Handle Data Analyst group name conflict (#70594)
There are 30 instances on stats with groups named "Data Analysts". We
need to handle this case.

First, we modify the migration:

- set `validCheckSum` to `ANY` to handle the case where this migration
already ran

- skip if there's already a `data-analyst` magic group

- insert a group named "Data Analysts", if one doesn't already exist

- otherwise name it "Metabase Data Analysts" (there are 0 groups on
with this name in cloud, theoretically it's possible but someone would
have to have BOTH `Metabase Data Analysts` and `Data Analysts` for this
to be an issue).

Similarly, we create a "Data Analysts" group on startup in OSS if one
doesn't already exist. This group is an invisible placeholder, that will
become visible if the instance ever upgrades. Adopt similar logic here:
if the existing group for data analysts is called "Metabase Data
Analysts", rename it to "Metabase Data Analysts (converted)" and create
the new placeholder group as "Metabase Data Analysts".
2026-03-10 14:02:47 -07:00
Edward Paget
c6a2880b31 Add mage dev-env task for isolated worktree dev environments (#70602)
* Add worktree dev environment tooling

Add `mage dev-env` task for isolated worktree dev environments with
Docker containers and deterministic per-worktree ports. Includes workmux
layout with nREPL dev server, frontend build, and nvim panes. Adds a
custom Claude Code Docker image with Clojure tooling via mise, and
a bin/claude-dangerous helper script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move dev-env mage task to personal -edpaget-dev-env task

Move the worktree dev environment tooling from the shared mage task
namespace (mage.dev-env) to a personal task namespace (mage.edpaget.dev-env),
remove the sample .workmux.example.yaml, and update .workmux.yaml hooks
to use the new command name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:01:59 -05:00
Jeff Bruemmer
5cd8e165fa docs - notes on timeouts (#70468)
notes on timeouts
2026-03-10 16:52:19 -04:00
Alexander Polyankin
05c26a4363 Clean up CODEOWNERS (#70666) 2026-03-10 14:32:41 -04:00
William
8ceeb1fce4 source replacement (#69257)
* fixes

* test parser changes

* schema test

* fix linter

* implicit join error

* fe tests

* fix linter

* test fixes

* more tests

* tests

* upgrade field refs for dashboardcard_series and dashboards in transitive deps

- Add dashboard-upgrade-field-refs! for Phase 1b: upgrades parameter_mappings
  on dashboards found in transitive deps (cards are upgraded first in Phase 1)
- Fix dashboard-card-update-field-refs! to find dashcards via
  DashboardCardSeries, not just by primary card_id
- Split dashboard-ids out of transitive in runner, pass separately to run-swap*
- Add tests for series card parameter mapping swap and dedup

* fixup some tests, add promise to progress instance

useful for test so we don't have to loop on the db row

```clojure
     (reify replacement.protocols/IRunnerProgress
       (set-total! [_ total] ...)
       (advance! [this] ...)
       (advance! [this n]
         (let [c    (swap! completed* + n)
               t    @total*
               prev (- c n)
               crossed-boundary? (or (= c t)
                                     (not= (quot prev progress-batch-size)
                                           (quot c progress-batch-size)))]
           (when crossed-boundary?
             (let [progress (if (pos? t) (double (/ c t)) 0.0)]
               (update-progress! run-id progress)
               (when (replacement.protocols/canceled? this)
                 (log/infof "Replacement run %d was canceled" run-id)
                 (when on-complete
                   (deliver on-complete :run/cancelled))  ;; <-----------
                 (throw (ex-info "Run canceled" {:run-id run-id})))))))
       (canceled? [_] ...)
       (start-run! [_] ...)
       (succeed-run! [_]
         (log/infof "Replacement run %d succeeded." run-id)
         (succeed-run! run-id)
         (when on-complete
           (deliver on-complete :run/success)))  ;; <--------
       (fail-run! [_ throwable]
         (log/errorf throwable "Replacement run %d failed" run-id)
         (fail-run! run-id (ex-message throwable))
         (when on-complete
           (deliver on-complete :run/fail))))     :<-----
```

and in tests we can do like so:

```clojure
(deftest advance!-progress-write-boundaries-test
  (testing "advance! writes progress at batch boundaries and on final item"
    (mt/with-premium-features #{:dependencies}
      (mt/with-model-cleanup [:model/ReplacementRun]
        (let [writes (atom [])
              done?  (promise)]
          (with-redefs [replacement-run/update-progress!
                        (fn [_run-id progress]
                          (swap! writes conj progress))]
            (let [record (replacement-run/create-run! :card 1 :card 2 (mt/user->id :rasta))
                  progress (replacement-run/run-row->progress record done?)]
              (execute/execute-async!
               (fn [progress]
                 (replacement.protocols/set-total! progress 120)
                 ;; advance one-at-a-time for 120 items
                 (dotimes [_ 120]
                   (replacement.protocols/advance! progress)))
               progress)
              ;; wait for virtual thread
              (is (= :run/success (u/deref-with-timeout done? 500)))  ;; <------------
              ;; Writes at items 50, 100, 120 (final) → progress 50/120, 100/120, 120/120
              (is (= [(double (/ 50 120)) (double (/ 100 120)) 1.0]
                     @writes))
              (is (=? {:is_active nil :progress 1.0 :status :succeeded}
                      (t2/select-one :model/ReplacementRun :id (:id record)))))))))))
```

* fixes

* add new flag to resolution

* fix

* fix sandboxing

* fix

* wip be

* wip  be

* wip be

* wip

* wip be

* wip be

* missing join-alias

* wip be

* more field ref cases

* wip be

* wip be

* wip be

* remove healing

* implicit join second level

* swap refactoring

* both loops process all

[GHY-3182: swap all dependencies](https://linear.app/metabase/issue/GHY-3182/swap-all-dependencies)

* field refs

* fix types

* fix ref types

* short curcuit when swapping

* base-type test

* fix order by

* test

* Viz settings in cards

* handle field->expression conversion

* base-type fix

* unique fix

* deduplicate test

* only upgrade/swap when well-formed query

`(-> card :dataset_query :stages seq)`

degenerate cases are `{}` and `{:lib/type :lib/query}`

* remove tests with broken schema

* test that :field -> :expression works in parameters, too

* viz_settings!

* legacy->pMBQL

* preserve native queries metadata

* fix typo in a comment

* Tests for field_refs.clj

* swap function order

* remove transitive card ids, add usages tests

we don't need to keep a set of all card ids. it's huge, and we're gonna
upgrade cards either way. So no need to not upgrade card references

* Fix upgrade-field-ref-to-name crash on :aggregation refs

Viz-settings locations (pivot_table.column_split etc.) can contain
[:aggregation 0] refs, not just [:field ...]. Wrap ->pMBQL in
with-aggregation-list so it can resolve legacy index-based aggregation
refs to UUID-based pMBQL. Add try/catch as safety net for other
unexpected ref types.

Fixes 13 cards failing with "no aggregation at index 0" error.

* fix expressions

* add a test

* fix the test

* add a proper test

* Skip non-field refs in upgrade-field-ref-to-name

Per Alexander's feedback: since we only resolve :field refs downstream,
skip :aggregation/:expression refs at the gate instead of setting up
aggregation context for ->pMBQL.

* remove log call in source-swap

* add schemas

* add schemas

* repro test

* guard against missing tables

* more fixes

* wip tests

* add tests for resolution with missing metadata

* Mutation testing improvements

* Some more tests

* revertme: adds comilation tracker for statsdb swap+upgrade analysis

* add checks for wrong queries

* fixes

* test fixes

* fix

* remove old code

* temp test fixes

* fix viz

* fixes

* One more tests.

* Singular mutation testing run

* tests

* fix tests

* remove not needed column checks

* fix tests

* run-swap throws with old-source new-source and check-result

* fix dependencies check test

```clojure
source-swap-test=> (clojure.test/run-test swap-native-card-source!-updates-dependencies-test)

Testing metabase-enterprise.replacement.source-swap-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
{:test 1, :pass 1, :fail 0, :error 0, :type :summary}
```

So an interesting bit:
we must update dependencies regardless. It's important that the dep
graph is updated. Imagine if Card A is swapped for Card B. All cards
that use Card A will be listed as deps of Card A even if they don't
reference it and don't require changes. We are still swapping the source
so we need to update the graph.

We don't have a real api for dependencies. So to ensure the cards are in
the graph we call `(events/publish-event! :event/card-create {:object
card :user-id (mt/user->id :rasta)})` and when swapping we prefer to use
`(models.dependency/swap-dependency! :measure entity-id old-source
new-source)`. But for dashboards we'll just do the full recompute
accomplished with

```clojure
(events/publish-event! :event/dashboard-update
                       {:object (t2/select-one :model/Dashboard :id dashboard-id)})
```

* working field-refs tests

* Fix logic

* Strong logic (but is it possible?)

* fix ::entity-id schema to include all entity types

* refactor

* fixes

* fixes

* fixes

* fixes

* fixes

* wip

* fix

* fixes

* fixes

* fixes

* fixes

* fixes

* fixes

* wip be

* wip be

* wip be

* remove unused

* wip be

* remove invalid queries

* wip fixes

* wip walk function

* Measure and segment tests

* fixes

* aliases

* fixes

* fix tests

* make source_swap accept the preloaded entity

* renaming

* unify sources

* database id fixes

* fix table id check

* deps fixes

* reflection warning

* fixes

* fixes

* fixes

* fix team

* fix CI

* check for admin

* disable plugin

* Disable api endpoints in prod

* wip tests

* fire events; namespace doc

```clojure
clj -X:dev:test:ee:ee-dev :only metabase-enterprise.replacement.source-swap-test
Ran 29 tests in 29.144 seconds
219 assertions, 0 failures, 0 errors.
{:test 29, :pass 219, :fail 0, :error 0, :type :summary, :duration 29144.393083, :single-threaded 29}
Ran 0 tests in parallel, 29 single-threaded.
Finding and running tests took 40.1 s.
```

All tests passing

Fire event only when things change, swap sources before. That's faster
and must happen regardless, change event only on change.

Namespace docstring indicating why

* fix constraint error if dependency already exists:

```
custom-swap=> (source-swap/swap-source! [:card 27452] [:card 6759] [:table 52728])
Execution error (PSQLException) at org.postgresql.core.v3.QueryExecutorImpl/receiveErrorResponse (QueryExecutorImpl.java:2736).
ERROR: duplicate key value violates unique constraint "idx_unique_dependency"
  Detail: Key (from_entity_type, from_entity_id, to_entity_type, to_entity_id)=(card, 27452, table, 52728) already exists.
```

it seems to have already have a dependency. So now we just remove
dependency if the one we are adding already exists, otherwise we swap.

swap card A: dep on B -> dep on C
if it already depends on C, just delete the dep on B
otherwise swap where card A dep B -> dep C

* simplify check

* upgrade parameter value_source_config

* field refs

* tests

* viz tests

* parameters

* tests

* fixes

* tests

* check sources fixes

* fix tests

* tests

* wip tests

* fixes

* wip tests

* wip tests

* wip tests

* wip cleanup

* cleanup

* move test

* lint

* fix

* fix

* fixes

* fixes

* fixes

* fix

* fixes

* fix

* fix

* fixes

* fix

* FE cache fixes

* fix checks

* fix

* polish: remove tracing code, update docstring, add :pending to ::run-status enum

* Add test for table->card in check-column-mappings

* Remove unneeded argument.

* Remove unused function.

* Test that all api endpoints are gated behind dependencies feature flag

* use api/*current-user-id* instead of (:id @api/*current-user*) in source swap

Avoids unnecessarily forcing the *current-user* delay (which loads the
full User record from the DB) when only the integer ID is needed.

* stop swapping card_id in parameters

* throw on partial swap failures so the run is marked as failed

Previously run-swap* returned {:failures [...]} which execute-async!
ignored, marking the run as succeeded. Now it throws with a descriptive
message (count + first 10 failures) that gets persisted in the run's
message column.

* Check that all routes are protected behind superuser

* Add test for runner.run-swap

* FE checks

* Remove source-error schema (unused)

* Reuse lib-be.schema.source-swap/column-error schema instead of remaking it

* Kondo error

* move code to lib-be

* Better mutation testing

* fixes

* More tests for field-refs

* Better test

* More source swap tests.

* suppress dependency event handlers during source replacement

Source replacement manages dependencies itself via swap-dependency!, so
the event-driven dependency recalculation, stale-marking, and metadata
propagation triggered by entity update events is redundant work.

Adds *suppress-dependency-events?* dynamic var, checked by all dependency
event handlers. Bound to true in run-swap* phase 2.

* Fewer deps! Yay!

* Revert "suppress dependency event handlers during source replacement"

This reverts commit 03625e9c26.

* Clearer code

* update 2 docstrings

* publish dashboard-update event only when a dashcard changed

* simplify implementation

* simplify

* bulk mbql replacement

* Revert "bulk mbql replacement"

This reverts commit cf12636c42.

* simplify

* fix reseting selection when the graph changes

* fix

* add source_swap module

* fix lint

* fix comment

* fix

* fixes

* fix module order

* fix module order

* fix order

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
Co-authored-by: Bryan Maass <bryan.maass@gmail.com>
Co-authored-by: dan sutton <dan@dpsutton.com>
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2026-03-10 14:25:01 -04:00
Fraser
49a3037d2a Move range-for-value into value (#70622) 2026-03-11 07:14:27 +13:00
Fraser
fa959aaab4 Remove deprecated getCurrentUser selector (#70558) 2026-03-11 07:13:06 +13:00
Kevin Kelleher
eadbd4b00d Fix broken pie chart colors for some strings in static-viz (#70640) 2026-03-10 13:53:45 -04:00
bryan
1da8e5751a Run Mage Tests on all PRs and fix module count (#70656) 2026-03-10 16:22:11 +00:00
Alex Yarosh
d47651a2cf docs: clarify transform perms (#70650)
clarify perms

Clarified the permissions required for viewing and executing transforms in Metabase.
2026-03-10 11:31:50 -04:00
Sébastien
92001b00de Fixed extraneous item in filter popover in embeds (#70634) 2026-03-10 16:17:24 +01:00
Sébastien
186c9dca65 Fix missing translation in guest embed filters (#70583) 2026-03-10 16:15:29 +01:00
Edward Paget
42aebbf137 Add configurable CSV field separator setting (#69827)
* Add configurable CSV field separator setting

- Adds csv-field-separator setting for configuring CSV export delimiter
- Supports comma (default), semicolon, tab, and other delimiters
- Useful for European locales where semicolon is standard
- Configurable via MB_CSV_FIELD_SEPARATOR environment variable
- Includes tests for different separator types and quoting behavior

Fixes #10256

* Split CSV separator tests into smaller deftests and clean up comments

Break the monolithic csv-field-separator-test into four focused tests:
- csv-field-separator-default-test
- csv-field-separator-semicolon-test
- csv-field-separator-tab-test
- csv-separator-quoting-test (already separate, just removed extra nesting)

Remove the "Changed from hardcoded" comment in csv.clj and the unused
metabase.test.util require.

* fixup! eastwood and serialization baseline

* fixup! whitespace

---------

Co-authored-by: kevin raymond <kevray39@gmail.com>
2026-03-10 09:55:03 -05:00
Eric Normand
df7d834e2e [Mutation Testing] Kill mutations in metabase.lib.field/find-visible-column-for-ref (#69320)
### Stats
- **Surviving mutations before:** 6
- **Tests added:** 2
- **Mutations killed by this PR:** 4
- **Mutations remaining:** 2

### Mutations killed
- Replace -1 with 0
- Replace field-ref with nil
- Replace :aggregation with :aggregation__
- Replace lib.metadata.calculation/returned-columns with nil

### Mutations not killed (with rationale)
- Replace some? with nil — Schema-only mutation — changing the Malli schema annotation does not affect runtime behavior
- Replace query with nil (in find-matching-column) — lib.equality/find-matching-column does not use the query arg for field ref matching in these test cases
2026-03-10 14:48:44 +00:00
Maksym Yakubych
bc7ffe094f feat: fix this query feature not using inline sql edits (#70172) 2026-03-10 11:06:04 -03:00
Ryan Laurie
205205174c Bump backport reminder threshhold to 25 hours (#70636)
bump backport reminder threshhold
2026-03-10 13:16:45 +00:00
John Swanson
05567456f2 Use virtualized table for data perms (#70343) 2026-03-10 09:01:10 -04:00
Kevin Kelleher
9bfb9ed7a4 Use lowest cardinality dimension as default for boxplot (#70569) 2026-03-10 08:49:24 -04:00
Kevin Kelleher
b161e19442 Fix handling of object columns in pie charts (#68095) 2026-03-10 07:22:13 -04:00
Uladzimir Havenchyk
c28beea344 chore: convert ObjectDetail viz to typescript (#70425)
* chore: convert ObjectDetail viz to typescript

* add column_title to viz definition type
2026-03-10 14:00:07 +03:00
Mahatthana (Kelvin) Nomsawadi
b22ab2010d Improve modular embedding analytics (#70449)
* Add v3 for modular embedding analytics

* Add implementation

* Improve test readability

* Improve code format

* Make the code autocomplete-able to prevent human-error

* Add missing default value tests

* Format

* Ensure we assert all properties

* fix "id_new" and "id_new_native" tracking

* Update the implementation so it count 0 like before

* Fix logic

* Fix snowplow schema lint

* Remove too much linear ticket number references
2026-03-10 10:54:58 +00:00
Jakub Chodorowicz
6f4d71c279 Gdgt 1801 Leaflet components (#70299)
* make LeafletMap generic component

* convert leaflet grid heatmap

* use filter guard to make sure we're dealing with L.Rectangle

* remove  param which doesn't exist

* add guard helper for data set column

* create LeafletMapPoint variadic generic type

# Conflicts:
#	frontend/src/metabase/visualizations/components/LeafletMap.tsx

* extact sync map from props methods

* migrate LeafletMarkerPinMap to TS

* don't force assert existence of pin dependencies

* use 3 tuple point everywhere in LeafletMarkerPinMap

* use ClickObject type

* migrate LeafletTilePinMap to TS

* convert LeafletChoropleth to TS

* remove type assertions in LeafletMarkerPinMap

* remove TileLayerWithInternals casting

* improve tile layer typings

* add casting comment

* improve embedding context types

* improve LeafletGridHeatMap types

* don't hardcode default scale for d3 scale linear

* call zoom control also when prevProps are missing

* improve HoveredObject, use HoveredObject in LeafletGridHeatMap

* remove unneeded nullish coalescence

* simplify getTileUrl by using just parameters as arguments

* remove unneeded assertion

* remove unneeded this param
2026-03-10 10:04:38 +01:00
Nicolò Pretto
c8d5e94ffa test(eajs): handleLink should prevent default behavior when returning {handled:true} (#70592)
test(eajs): handleLink should  prevent default behavior when returning {handled:true}
2026-03-10 09:43:31 +01:00
Ngoc Khuat
22a1f275f0 Fix computed transform tables being editable (#70441) 2026-03-10 14:54:23 +07:00
Nathan Voxland
9bd22bf4b1 Added dedup-fn feature 2026-03-10 02:03:18 -05:00
mendral-app[bot]
ce8660f161 Use env vars for embedding workflow (#70614)
fix: prevent script injection via PR title in embedding-sdk workflow

Move user-controlled PR context values (title, number, URL) and secrets
from direct GitHub Actions expression interpolation into env vars.
This prevents a crafted PR title from breaking out of the shell string
and executing arbitrary commands on the runner.

Co-authored-by: mendral-app[bot] <233154221+mendral-app[bot]@users.noreply.github.com>
2026-03-10 06:51:16 +04:00
Denis Berezin
dcf260f4c9 Fix broken e2e test for #68998 (#70585) 2026-03-10 03:24:04 +03:00
Aleksandr Lesnenko
4897452a08 Metrics Explorer (#68961)
Co-authored-by: Edward Paget <ed.paget@gmail.com>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
Co-authored-by: John Swanson <john.swanson@metabase.com>
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Kevin Kelleher <kevin.kelleher@metabase.com>
Co-authored-by: Maz Ameli <maz@metabase.com>
2026-03-09 20:18:15 -04:00
dpsutton
c87ad18e21 quarantined driver notifications (#70612)
* quarantined driver notifications

* temp on push to bot-testing channel

* prettier

* more compact

* add back a bit of emphasis

* remove push edge and restore channel
2026-03-09 18:14:56 -05:00
Fraser
78a8c59d71 Move expandable string to where it's used (#70559) 2026-03-10 12:08:58 +13:00
Fraser
336c2a8b1a Convert OnClickOutsideWrapper to TypeScript (DEV-1496) (#69418)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:50:54 +13:00
Rodrigo López Dato
567bbd68bb Clarify that SSO provisioning also allows reactivating accounts (#67524)
* Clarify that SSO provisioning also allows reactivating accounts

* Update wording in docs

* ditto LDAP

* Use radio buttons instead of a toggle

* lint/wording

* lint

* Revert changes to autogenerated docs

* Fix eslint rule + improve wording

* Make OIDC provisioning setting consistent with other providers

* Add detailed descriptions only to env var docs, not UI

* Fix E2E test

* fix: update ESLint configuration file path from .eslintrc.js to eslint.config.mjs

* run lint when we change component tests specs

* fixing linting

* ignore linting issue in embedding test

---------

Co-authored-by: Nicolò Pretto <info@npretto.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2026-03-09 18:09:00 -03:00
Braden Shepherdson
ba6895665f [MBQL lib] Ignore inherited-temporal-unit on bucketed columns (#70512)
Fixes QUE2-394.

This issue was caused by losing the thread of a column between stages in
the case where it has a different `:inherited-temporal-unit` than its
proper `:temporal-unit`.

`lib.equality/=` was checking the `:temporal-unit`s, which match, and
then returning `false` because only one column had
`:inherited-temporal-unit` for a different, finer unit. That shouldn't
fail the match, since the `:inherited-temporal-unit` is obsolete when
the column has just been bucketed differently.
2026-03-09 21:02:10 +00:00
Ben Grabow
09c04d91bb Remove minimally useful semantic search log messages (#70524) 2026-03-09 21:01:38 +00:00
Jeff Bruemmer
8977542307 docs - remote sync limitations (#70598)
* branch limitations

* edits

* link

* Apply suggestions from code review

Co-authored-by: Alex Yarosh <alexandra@metabase.com>

---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-03-09 20:51:35 +00:00
Ben Grabow
ec678a17fc Uxw 1070/fail early if unsupported appdb version is detected (#70402) 2026-03-09 15:33:16 -05:00
Chris Truter
6eda44fc53 Fix reflection warnings in tests + add linter (#70551) 2026-03-09 13:29:04 -06:00
metamben
4219500b7a Preserve expression names when fixing bad field refs (#70530)
Closes QUE2-397
2026-03-09 21:48:51 +03:00
Will Bryant
2f2ab17ebb Fix race condition in FormattingWidget initialization (#69777) (#69778)
Although there was an early return if isLoading is true, the useState had already run, and set the state to the DEFAULT_FORMATTING_SETTINGS. This would then not get replaced when isLoading became false.

Instead, use the same idiom as SessionTimeoutSetting - install a useEffect hook that depends on the setting value and applies that setting value to the local state.
2026-03-09 11:43:20 -07:00
Nathan Voxland
0462cde56d Fixed kondo 2026-03-09 11:14:43 -05:00
Maksym Yakubych
89c1712267 fix: Metabot not receiving transform errors from transforms (#70462) 2026-03-09 15:54:48 +00:00
Nicolò Pretto
ba03f8d368 remove ThemeProvider from sdk component test (#70568) 2026-03-09 16:51:29 +01:00
Edward Paget
6d84d80c06 fix: allow dashboard caching in read-only mode (#70511)
* fix: allow dashboard caching in read-only mode

* fix: split out cache permissions from can-write?

We were denying changing caching policy for dashboards on read-only
remote-synced instances because we set can-write? to false for
dashboards when we are in read-only mode.

we also need to create a new boolean flag we can return to the frontend
to indicate that caching is still allowed even when editing a dashboard
is otherwise disabled.

* fixup! PR feedback
2026-03-09 10:37:16 -05:00
Nathan Voxland
e99312fe64 Renamed def-listener to def-listener! 2026-03-09 10:24:36 -05:00
Denis Berezin
b130d0d812 Pivot Table shows a blank card when rendered on a dashboard (#70385) 2026-03-09 18:18:37 +03:00
Riley Thompson
caafceff99 Upgrade clickhouse to 0.9.7 with pinned dependencies (#70448)
* upgrade clickhouse jdbc to 0.9.7

* clean up todos

* update deps
2026-03-09 11:12:36 -04:00
Jakub Chodorowicz
5fe95dbbae fix self-heal openapi job and update openapi.json (#70499) 2026-03-09 15:42:44 +01:00
Nicolò Pretto
65d9029a55 fix: update ESLint configuration file path for eslint config (#70507)
* fix: update ESLint configuration file path from .eslintrc.js to eslint.config.mjs

* run lint when we change component tests specs
2026-03-09 13:32:17 +00:00
github-automation-metabase
e4ec44c4af Auto-update documentation for master (#70560)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-09 09:28:12 -04:00
Uladzimir Havenchyk
0e9fd4c48c add transform-basic feature flag for transforms (#70442)
* add another feature flag for transforms

* fix linting error from master

* add debug info

* enable-transforms-basic -> enable-basic-transforms

* remove logs
2026-03-09 15:08:51 +03:00
Phoomparin Mano
cd32f3b89c Integration branch for embedding onboarding improvements (#69456)
* Add "configure data permissions and enable tenants" skeleton for onboarding (#68895)

* use onboarding stepper

* add TODO for EMB-1266

* add e2e test for skeleton

* use gap=sm for steppers

* align with design

* Add completion checks for data segregation and tenants (#68890)

* add completion information for segregation and tenants

* add data segregation checks

* add data segregation config test

* add the combined data-permissions-and-enable-tenants step

* separate main and sub checklist

* explain the purely ui step

* add schema for checklist response

* update checklist completion states

* add test cases

* address review on test permutations and using is_active for tests

* remove stale configure data permissions unit test

* remove stale test on user strategy card

* Add enable tenants and create shared collection button (#69131)

Add enable tenants and create shared collection button (#69131)

* Add data segregation strategy selection step for embedding onboarding (#69127)

Add data segregation strategy selection step for embedding onboarding (#69127)

* Lock steps 2 to 5 in data permissions setup checklist (#69135)

Lock steps 2 to 5 in data permissions setup checklist (#69135)

* Add link to documentation for database routing in the onboarding step (#69138)

Add link to documentation for database routing in the onboarding step (#69138)

* Add tenant creation and tenant summary step for tenants onboarding (#69454)

Add tenant creation and tenant summary step for tenants onboarding (#69454)

use index as key instead

update failing unit test

refactor: use slugify instead

add assertion on configure data permissions step should be done

cleanup summary components

adjust font size

use related setting card for summary

refactor: cleanup card components

add e2e test verifying tenant errors are shown

add e2e test verifying tenants are created

fix: prevent going to previous incomplete step

fix: skip locked steps

fix: consider locked steps when auto-advancing

fix: failing e2e by enabling tenants via ui

refactor: cleanup tenants import

add fallback logic for tenants listing

refactor: move onboarding step to tenants plugin

scaffold tenant summary step

scaffold tenant creation step

use paper from mantine-ui instead

scaffold tenant creation step

* Onboarding stepper should navigate to next steps correctly even when all steps are done (#69653)

Onboarding stepper should navigate to next steps correctly even when all steps are done (#69653)

cleanup: remove redundant test

fix: cleanup broken tests

remove inapplicable test case

apply onboarding stepper fixes

* Add row and column level security step for onboarding (#69622)

fix failing e2e tests

wait for permission graphs to update before checking error toasts

add test assertion on hiding selected tables

hide tables that are selected by other cards

add unit test for building permissions graph

address review on type-safe sandbox policy

extract error and success toasts into UI consumer

add clarification on why we assert GTAP

extract MiniPicker hard-coded margins to the data picker call site

address review on using design system units and rem

address review on "All tenant users" permission update hook

Add row and column level security step for onboarding

revert all changes to OnboardingStepper

update the permission graph as well

refactor: renamings

lock step "Select data to make available" if strategy not chosen

cleanup: remove button

use metabase/ui for select style

refactor: extract table column card

simplify trigger styles

revert MiniPicker change

undo test name change

refactor: simplify stepper

update e2e test assertions

add step completion assertion to e2e tests

refactor: extract to step components

allow going to next step

fix onboarding stepper re-rendering

chore: cleanup sandboxing creation test

add e2e tests

add sandbox on clicking next

clicking next on rls selector should advance to next step

refactor: rename to selections and onSelectionsChange

display options on the bottom

position dropdown directly below the trigger

fix: trigger height

fix: do not hide title on RLS step

do not collapse current step when all steps are complete

make it clearer what is goToNextIncompleteStep

simplify logic for going to next incomplete step

add data selector for row and column security

* Create a multi-select database selector component (#69635)

Create a multi-select database selector component (#69635)

chore: remove fluff tests

allow disabling rightSection with null

add data fetching to DatabaseMultiSelect

use multi autocomplete

add storybook story and unit test for disabled options

allow disabling database options

update multi select tests

chore: formatting

cleanup dropdown style

show placeholder always

apply brand focus color

remove inline-end

limit combo box width

update styles to match figma design

update option icon

scaffold database multi select

* Add connection impersonation onboarding step (#69644)

Add connection impersonation onboarding step (#69644)

add permission graph and impersonation assertion

add e2e test

use useUpdateTenantGroupPermissions for permission updates

add connection impersonation creation hook

add edge case for database does not support impersonation

disable dbs without connection impersonation

scaffold ui for connection impersonation

* Add JWT authentication onboarding for embedding hub (#69823)

test: e2e fail due to lock icons found in related settings section

replace e2e test on jwt completion

update e2e tests

scaffold e2e tests

refactor: cleanup sso stepper component

add help url and complete step button

scaffold "Test that JWT authentication is working correctly" step

scaffold "Add a new endpoint to your app" step

add ui to configure identity provider

scaffold sso setup

* Mark get embed snippet step as done when guest embed is published (#69889)

* mark guest embedding onboarding test step as done

* add e2e test for guest embed

* simplify e2e test

* fix invalid imports due to merge conflicts

* fix guest embed snippet copy incorrectly marking production embed step as done

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Embed wizard should default to newly created dashboards (#69907)

Embed wizard should default to newly created dashboards (#69907)

scaffold defaulting to newly created dashboards

add a comment on why newly created dashboards are prioritized

chore: update inline comments

de-duplicate recent items at call site

refactor: cleanup implementation

add created_at time filter

address review feedback on variable naming

address review by going through actual x-ray flow

remove invalid unit test

update duplicated and failing tests

fix failing tests

fix failing select-embed-experience e2e test

fix failing select-embed-entity e2e test

* Remove create models step from embedding onboarding checklist (#70256)

remove create models step

* Show tenant_identifier autocompletion from column values in RLS (#69829)

Show tenant_identifier autocompletion from column values in RLS (#69829)

scaffold basic tenant_identifier autocompletion

make placeholder dynamic to tenant identifier input

fix: update broken types

document why we use ad-hoc query

refactor: small cleanup

cleanup docstring

chore: update hook tests

add e2e tests for autocompletion

explicitly pass tenant attributes

simplify CreateTenantInput

Suppress ad-hoc query errors in tenant identifier autocomplete

Autocomplete suggestions are best-effort during onboarding. Query
failures (permissions, timeout, etc.) should not surface global
error UI noise.



Make attributes optional in CreateTenantInput to match API contract

The backend marks attributes as optional; the frontend type was
overly strict and forced callers to always send attributes: {}.



Derive selectedFieldIds from sandboxedTables, not tableColumnSelections

Previously, field IDs were extracted from all tableColumnSelections,
including entries skipped because the table failed to fetch. Now we
only include IDs from policies that were actually applied, deduplicated.



Use stable placeholder and aria-label in TenantIdentifierInput

The old dynamic placeholder (first suggestion value) looked pre-selected
to users. Now prefix with "e.g." using c().t for localization context,
falling back to "e.g. acme-corp" when no suggestions are loaded. Also
adds aria-label for accessible and stable test targeting.



Update E2E tests to use "e.g. 1" placeholder for tenant_identifier input

The placeholder is now prefixed with "e.g." to clarify it's an example.
This also implicitly validates that autocomplete suggestions were fetched
successfully, since the placeholder is dynamic when data is available.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Tenant creation should differ the data isolation field by strategy (#70258)

Tenant creation should differ the data isolation field by strategy (#70258)

scaffold implementation on tenant isolation fields

refactor: use ts-pattern for isolation field config and label lookups

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

update checklist endpoint to return checklist separate from isolation strategy field

refactor: use dataIsolationFieldValue field for creating tenants

fix: use activeStrategy for reload-aware strategy picker and step content

On page reload, selectedStrategy is null but activeStrategy is populated
from the backend. Switch the data segregation picker value, select-data
step lock condition, title hide flag, and match expression to use
activeStrategy so the correct state is reflected on reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

tweak tenant name styling

always require data isolation strategy field value to create tenants

update embedding hub checklist backend test

add e2e tests for reload and isolation strategy

fix: remove hard-coded string in tenant identifier input

refactor: move DataSegregationStrategy type to embedding-hub types module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

refactor: remove single-letter variables

* Show segregation strategy specific data permissions in tenant summary (#70268)

Show segregation strategy specific data permissions in tenant summary (#70268)

show segregation strategy specific summary

test: add unit tests for getDataPermissionsDescription

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

fix: add selectedFieldIds to TenantsSummaryOnboardingStep plugin interface

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

add e2e test assertions and test cases

simplify row-level security summary logic

fix rls imports

update data permission description span

add bold text to description summaries

fix failing e2e tests

fix starter test failing

remove focused test

update comment on the rls e2e test

fix: use singular 'table' for single-table RLS data permissions description

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

add a comment on why RLS needs the same column

use conjunct method for string formatting

simplify textFromReactNode

simplify getDataPermissionsDescription unit test

chore: code formatting

remove route title

fix: failing test due to placeholder update

remove the starter test as it does not apply

fix: reset hiddenParameters when switching from guest to SSO embed mode for dashboards

When recentlyCreatedDashboards pre-populates the dashboardId, the resource loads
in guest mode and initializes hiddenParameters with all parameters as disabled.
Switching to SSO now resets hiddenParameters to [] for dashboard embeds, matching
the existing behavior for question embeds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

fix ignore_error flag

fix: incorrect test assertion for database selector

fix: incorrect placeholder assertion

* Tenant users are unable to query database after onboarding flow (#70476)

Tenant users are unable to query database after onboarding flow (#70476)

fix(embedding): set create-queries permission for RLS tenant users

Tenant users with RLS could view dashboards but were unable to query
the database because the permissions graph only set `view-data` without
`create-queries`. Add `"create-queries": "query-builder"` at the
database level for both sandboxed and impersonated configurations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

fix: update unit tests on embed settings

fix failing tests due to parameters reset

* Polish tenant creation and SSO for embedding onboarding (#70477)

Polish tenant creation and SSO for embedding onboarding (#70477)

polish permissions setup and create tenants onboarding

update copy for tenant identifier

* fix(type): add rlsColumnName type to plugin defs

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:02:34 +07:00
Fraser
6d79bbc173 Stop using 2am in tests to avoid DST issues (#70562)
* Stop using 2am in tests to avoid DST issues

* Scope to table cell data
2026-03-09 07:41:57 +00:00
Nathan Voxland
d8a7cd3501 Fixing tests 2026-03-08 01:41:38 -06:00
Eric Normand
7c8125d4bb Fix typo in self-dependency removal GHY-3198 (#70535)
There was a typo in a transducer where the cat and remove were swapped. The cat was meant to combine collections (`#{x})` and the remove was looking for `x`, but since it happened in the wrong order, it never removed them. This led to self-dependent entities, and therefore cycles which caused infinite loops.
2026-03-07 21:58:17 +00:00
Chris Truter
54439261a4 Fix case sensitiviy issues with workspace query execution (#69350) 2026-03-07 07:35:50 +00:00
Nathan Voxland
2d2c4b35a5 Fixing tests 2026-03-07 01:25:05 -06:00
Nathan Voxland
9e717a6056 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	resources/migrations/059_update_migrations.yaml
2026-03-07 00:09:19 -06:00
Nathan Voxland
9ed603e6ce Better multi-backend handling 2026-03-06 17:30:39 -06:00
Maz Ameli
18706c2456 Switch component improvements (#70520)
* fix toggle alignment

* reduce space above description

* change usage guidelines to recommend sm

* Update Loki Snapshots

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-03-06 22:57:08 +00:00
Nathan Voxland
8a5545ad32 Fixed whitespace and migrations 2026-03-06 16:01:30 -06:00
Chris Truter
3d5b673c9a Support template tags in Workspace transforms (#69561) 2026-03-06 21:21:37 +00:00
Nathan Voxland
82b89e31fb Fixing tests 2026-03-06 15:09:41 -06:00
Chris Truter
0e1325ba1e Implement scoped authorization to limit API surface (#70372) 2026-03-06 23:01:36 +02:00
Jacob Joseph
9c801dfbd9 Fix numbered list for row and column security section (#70525) 2026-03-06 20:31:04 +00:00
Nick Fitzpatrick
c27eee3f51 ignore linting issue in embedding test (#70514) 2026-03-06 16:13:58 -04:00
Maksym Yakubych
1cfc71fed7 fix: NLQ profile incorrectly used for SQL editor requests (#70436)
* fix: NLQ profile incorrectly used for SQL editor requests

* fix: tests
2026-03-06 12:55:40 -06:00
Nathan Voxland
619f2b2be6 Add repro-bot github workflow (#70435) 2026-03-06 11:02:20 -06:00
Nick Fitzpatrick
64978428b8 fixing linting (#70504) 2026-03-06 16:55:14 +00:00
dpsutton
58d2cd37b6 bump c3p0 to 0.12.0 (#70494) 2026-03-06 09:36:34 -06:00
Nicolò Pretto
6901847ed2 remove noisy logs from sdk component tests (#70416)
* should fix clj files imported from sdk component tests

* reduce noise when not finding the sdk package

* remove mantine from tests that don't need it

* eslint rule
2026-03-06 16:32:49 +01:00
Nicolò Pretto
10286754ee feat(sdk): speed up the embedding sdk loading time: do auth flow in parallel with bundle loading and split the bundle in chunks (#70015)
* test ci

* fix

* fix e2e

* make linters happy?

* more ci fixes

* more ci fixes

* maybe fix flake

* more ci things?

* more things including a test that we do fallback to old auth

* remove un-needed changes

* more cleaning

* make tests more stable

* clean up debug comments

* remove ! that was not needed

* fix broken build

* cleanup

* more cleaning up

* more cleanup

* clean up consts

* more cleaning up and saml bail out tests + logic

* revert uneeded change in copy js plugin

* better comments and renamed chunk auth function

* merge test files, fix double auth requests done due to missing redux dispatch

* fix typo in backend comment

* fixed version of renaming param to useLegacyMonolithicBundle

* remove cy wait

* remove wait + fix matcher on request for dev mode to not match map file

* clean up tests

* remove empty lines from gitignore

* remove unrelated gitignore change

* r emove imports

* cleanup tests from redundant tests

* remove other un-needed code

* comments

* add date to a TODO as suggested by Kelvin

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* rename checkForAuthConfig -> checkForAuthConfigAndStartAuth

* startAuth -> startJwtAuth

* use new URL to construct baseUrl

* use shared auth  logic

* use the real version as we can actually

* add comment on numTestsKeptInMemory usage

* add test about path traversal

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-06 14:51:25 +00:00
Nicola Mometto
8f1606adc5 Allow loading of 58 serialized tables in 59+ (#70486)
* fix: allow importing 58 serialized data-layer values

* add test
2026-03-06 14:13:16 +00:00
Ngoc Khuat
5b6e3071ac Fix duplicate alerts/subscriptions firing in multi-pod clusters (#70474)
* Fix duplicate alerts/subscriptions firing in multi-pod clusters

Set acquireTriggersWithinLock=true to force pessimistic locking during
trigger acquisition. Without this, Quartz uses an optimistic UPDATE that
is vulnerable to an ABA race condition where multiple cluster nodes can
acquire and fire the same trigger simultaneously.

* Add *warn-on-reflection* to custom_migrations/util

Fixes clj-kondo warning triggered by Java interop (System/setProperty,
System/clearProperty) added in the acquireTriggersWithinLock fix.
2026-03-06 10:35:46 -03:00
Edward Paget
76e96af834 fix: only skip deleting commonpy not pushing it (#70439)
* fix: only skip deleting commonpy not pushing it

* fixup! kondos
2026-03-06 07:16:39 -06:00
Sébastien
92017bab3f fixed table width in guest embed (#70418)
* fixed table width in guest embed

* fixed test
2026-03-06 14:10:57 +01:00
Ngoc Khuat
c86caa092e Unifying source tables transform format (#70298) 2026-03-06 18:48:41 +07:00
Jakub Chodorowicz
29590b8e09 Fix TS failure - duplicated selectors (#70480)
remove duplicated selectors
2026-03-06 10:07:41 +00:00
Ngoc Khuat
e822288497 GDGT-1872: Change transform metering to tier-based keys (#70366) 2026-03-06 05:46:42 +00:00
Nathan Voxland
607985e054 Fixing tests 2026-03-05 22:15:42 -06:00
Nathan Voxland
a2e43e1996 Fixing tests 2026-03-05 21:23:23 -06:00
Noah Moss
a6c90cc7ff Filter out inactive tables for metabot (#70440)
* Filter out inactive tables for metabot

* fix another spot
2026-03-05 23:02:01 +00:00
Riley Thompson
1571e58188 Data migration to fix clickhouse upload dbs with missing schema (#70363)
* testing

* add migration

* add test

* reorder test

* improve migration

* improve test

* add comment explanation

* fmt
2026-03-05 17:05:33 -05:00
Fraser
ae1e0d6311 Convert admin/people/selectors to TypeScript (#69431)
* Convert `admin/people/selectors` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1509

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add people property to AdminState type

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 10:57:15 +13:00
Fraser
3f547462c9 Convert linked-filters to ts (#70045) 2026-03-06 10:57:01 +13:00
Nathan Voxland
3b96cd4619 Deps fix 2026-03-05 15:56:10 -06:00
Nathan Voxland
31790b6052 Added def-listener! and fixing tests 2026-03-05 15:42:23 -06:00
Jeff Bruemmer
05aaad4f3a README - updates (#70460) 2026-03-05 16:02:15 -05:00
Ben Grabow
92ec0df7b1 Ignore some generated files (#70454) 2026-03-05 14:56:22 -06:00
metamben
35b542b651 Fix column-metadata->field-ref-source-alias-test (#70458) 2026-03-05 20:21:57 +00:00
Cam Saul
ab7e4712b1 Omit pivot-grouping from window function OVER PARTITION BY and ORDER BY expressions (#70273)
* Experimental fix for #70088

* cljfmt

* Document the new key

* Cleanup
2026-03-05 10:31:07 -08:00
Maksym Yakubych
47471f9518 fix: metabot returns null for pasted question references (#70388) 2026-03-05 12:23:16 -06:00
Eric Normand
86868639b4 test: mutation tests for column-metadata->field-ref (#69342)
* [Mutation Testing] Add tests for metabase.lib.field/fieldable-columns

* test: mutation tests for column-metadata->field-ref source-alias propagation

Tests the MEGA HACK source-alias-to-join-alias propagation in column-metadata->field-ref:
- Verifies source-alias becomes :join-alias for table-default columns
- Verifies inherited columns do not propagate source-alias
- Verifies inherited columns do not get non-inherited propagated keys

Kills 6 more mutations (51/60 total, 9 unkillable due to schema constraints).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:23:21 -05:00
Eric Normand
c61c93e825 test: mutation tests for add/remove field operations (#69329)
* [Mutation Testing] Add tests for metabase.lib.field/fieldable-columns

* test: mutation tests for add-field, add-field-to-join, remove-field, remove-field-from-join

Adds tests that kill surviving mutations:
- add-field: expression column with explicit :fields (kills :source/expressions mutation)
- add-field-to-join: join with :none fields (kills 5 mutations)
- remove-field: expression column removal (kills :source/expressions mutation)
- remove-field-from-join: join with :none fields (kills 4 mutations)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:44:10 -06:00
Filipe Silva
6dfde80586 rfct: remove superfluous comments (#69099)
Fix https://github.com/metabase/metabase/pull/68478#discussion_r2760627013
2026-03-05 15:48:59 +00:00
Nemanja Glumac
009911d60a Fix incomplete URL substring sanitization in LeafletMap (#70428)
The previous check used `.includes("openstreetmap.org")` which could be
bypassed by malicious domains like `openstreetmap.org.evil.com` or
`fake-openstreetmap.org`.

This fix validates that the hostname is either exactly `openstreetmap.org`
or a legitimate subdomain ending with `.openstreetmap.org`.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-05 14:40:14 +00:00
Braden Shepherdson
237bbe2919 [MBQL lib] Unexport lib.options namespace (#70276)
Fixes QUE2-351.

I added a new exported function `lib/ignore-case`, since some drivers,
test, and Metabot were using `lib.options/update-options` to set
`:case-sensitive false` on `:contains` et al clauses.

`lib.options` is only used by friends now (mostly QP).
2026-03-05 14:28:44 +00:00
Oleksandr Solovyov
c8b1767e66 Semantic search speedup (#70317)
* do not put embeddings in metadata json for semantic search
* semantic search: filter personal_owner_id right in the database
* simplify batch-update code
2026-03-05 15:18:13 +02:00
Uladzimir Havenchyk
18e327042f chore: drop unnecessary react imports (#70415) 2026-03-05 16:00:30 +03:00
Alberto Perdomo
f02d26aa14 EMB-1329: update embed wizard terms copy and add link (#69856)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Phoomparin Mano <poom@metabase.com>
Co-authored-by: Nicolò Pretto <info@npretto.com>

closes #69302
Closes linear.app/metabase/issue/EMB-1329/embedding-tooltip-directs-you-to-read-license-text-linked-above-no
2026-03-05 11:58:06 +00:00
Timofey Kachalov
8056c1835a fix(sdk): Fix the empty container detection in SDK question layouts (#70389) 2026-03-05 15:40:13 +04:00
Kevin Kelleher
04055423f0 Admin TS conversions (#69825) 2026-03-05 06:37:33 -05:00
Nathan Voxland
846f38d443 Fixing tests 2026-03-05 02:00:51 -06:00
Uladzimir Havenchyk
4e7d009a53 chore: convert Text visualization to typescript (#70364)
* chore: convert Text visualization to typescript

* fixup
2026-03-05 10:28:55 +03:00
Nathan Voxland
e7a9e8c100 Removed other settings cache sync code 2026-03-05 01:20:07 -06:00
Nathan Voxland
e1b7b8e912 Use new queue better in search 2026-03-05 00:46:36 -06:00
Romeo Van Snick
a41303a180 Wrap buttons and title on smaller screens (#67681)
* Wrap title and buttons earlier when nav bar is open

* Wrap title in header at wider breakpoint

* Left align ad-hoc questions too

* Add gap when question title collapses

* Increase breakpoint

* Fix padding on ViewSection

* Use container query for query builder breakpoints

* Make padding more consistent with other headers on small screens

* Tweak question action buttons on small screens

* Add separator for actions

* Fix padding on filter panel

* Fix padding on back button

* Fix padding to match header

* Break sooner

* Do not break subheader as soon

* Fix test

* Remove reliance on query-builder from FilterPanel component

* Remove spurious margin

* Fix gap between header items

* Move container to header and footer
2026-03-05 15:02:09 +11:00
Fraser
8474a8f7f5 Convert metabase-lib utils to ts (#70044) 2026-03-05 16:24:06 +13:00
Anderson
2b61cce77b Don't call trial check EE endpoint in OSS for Remote Sync upsell (#70349) 2026-03-04 21:16:03 -05:00
Riley Thompson
0a0625d163 Revert "Upgrade clickhouse jdbc driver to 0.9.7" (#70403)
Revert "Upgrade clickhouse jdbc driver to 0.9.7 (#70387)"

This reverts commit 3a69ad8f49.
2026-03-04 16:50:23 -08:00
Jeff Bruemmer
bb42762372 docs - keys to data studio (#70405)
* keys to data studio

* link
2026-03-04 18:04:50 -05:00
Alexander Polyankin
420c4e27e0 Add writable-connection feature flag (#70287) 2026-03-04 15:54:40 -07:00
Romeo Van Snick
7d8f3849bf Polish transform template tag frontend (#70095)
* Rename confusingly named setParameterAttribute

* Remove unnecessary check

* Add options to disable parameter settings

* Disable parameters settings in transform sidebar

* Add e2e test for parameter field settings

* Rename disableParamaterSettings to parametersAreUserVisible

* Make parametersAreUserVisible configurable all the way up to QueryEditor

* Update copy when parameters aren't visible to user

* Fix test
2026-03-04 13:37:06 -08:00
Denis Berezin
def46a7c0c Update jspdf to fix security issues (#70393) 2026-03-04 23:28:10 +03:00
Riley Thompson
3a69ad8f49 Upgrade clickhouse jdbc driver to 0.9.7 (#70387)
* upgrade clickhouse jdbc to 0.9.7

* clean up todos
2026-03-04 19:22:08 +00:00
metamben
3a62030c09 Generate different column group names for joins to the same table (#70119)
* Generate different column group names for joins to the same table

Closes QUE2-180
2026-03-04 18:52:17 +00:00
metamben
8a93fb4fcd Make excluded-datetime return integers for days too (#69915)
* Make excluded-datetime return integers for days too

Closes QUE2-254
2026-03-04 18:24:04 +00:00
Egor Grushin
483117981c DEV-1599 DEV-1598 fix flakiness (#70166) 2026-03-04 17:51:33 +00:00
Nathan Voxland
2480ce058b Support exclusive queue listeners 2026-03-04 11:27:19 -06:00
Nathan Voxland
cf04ba48c2 Immediately deliver topic posts locally without waiting for backend roundtrip 2026-03-04 09:51:00 -06:00
Nicola Mometto
88f48ce996 Restrict notification schema and allowed template values (#70261)
* fix: restrict channel renderer to hbs files in the template path

* restricted api schemas

* explicit validation

* chore: tests

* fix: test
2026-03-04 15:23:35 +00:00
Rodrigo López Dato
7eb9d27107 Conceal JWT signing secret by default (#70329) 2026-03-04 11:50:29 -03:00
Nemanja Glumac
c5b8eef4d9 Add cache restore keys for M2 and Node modules (#70370) 2026-03-04 14:17:36 +00:00
Chris Truter
9c44b33887 Add malli typing for transform execution methods (#70250) 2026-03-04 13:23:12 +00:00
Nicola Mometto
3b030bcd58 fix test after out-of-order merge (#70368) 2026-03-04 13:01:13 +00:00
Nicola Mometto
4b9c2e7720 support multiple join conditions in join-analysis lens (#70247)
* fix: count on the condition rather than trying to extract field, generalized for multiple join conditions

* chore: tests

* fix: inline
2026-03-04 11:59:29 +00:00
Chris Truter
57586f2427 Extract non-appdb module out of transforms (attempt #3) (#70245) 2026-03-04 09:50:35 +00:00
Stas Gavrylov
d813be6b09 GDGT-1755: Migrate AdHocQuestionLoader, Breadcrumbs, QuestionLoader, QuestionResultLoader, SavedQuestionLoader to TS (#70106)
* Migrate AdHocQuestionLoader component to TS

* Migrate Breadcrumbs to TS

* Migrate QuestionLoader, QuestionResultLoader, SavedQuestionLoader to TS

* GDGT-1755: Add type guards for Breadcrumbs

* GDGT-1755: Restore comments

* GDGT-1755: Address review comments

* GDGT-1755: Fix tests

* GDGT-1755: Rename type
2026-03-04 11:30:20 +02:00
Chris Truter
ccd3e61ff0 Fix clickhouse transform flake, hopefully (#70316) 2026-03-04 08:49:54 +00:00
Nathan Voxland
8a853116bf Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	.clj-kondo/config.edn
2026-03-04 01:26:56 -06:00
Nathan Voxland
c54c9ded12 improving code 2026-03-04 01:20:12 -06:00
Nathan Voxland
0fc1a4b8c9 Code improvements and removed postgres topic listener 2026-03-04 00:18:19 -06:00
Ben Grabow
5e647df5be Add bgrabow (#70347) 2026-03-03 22:18:36 +00:00
Braden Shepherdson
04a5c90dab [MBQL lib] Move lib.util/join-strings-with-conjunction to util.i18n (#70270)
Fixes QUE2-371.

This function has nothing to do with lib, and only depends on
`clojure.string`.
2026-03-03 22:13:40 +00:00
Nathan Voxland
bbc00a8677 Don't fail on unknown settings when calling set-many (#70282) 2026-03-03 15:57:10 -06:00
Nemanja Glumac
a43d62a505 Disable scheduled cloverage reports (#70313) 2026-03-03 22:39:11 +01:00
Ben Grabow
693ac2a9ce Make a mage task to generate resolve-as XML from clj-kondo lint-as data (#70342) 2026-03-03 15:33:17 -06:00
Alex Yarosh
d4a888c2ec docs: a lot of updates (#70176)
* oops

* links

* more links

* Update docs/configuring-metabase/appearance.md

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-03-03 20:39:03 +00:00
Alex Yarosh
73a53fd72d docs: update default target branch for docs autogen (#70334)
Update default target branch to release-x.59.x
2026-03-03 20:04:50 +00:00
Abed Habli
7a88dfba69 Docs V59: Adding profile icon for non-admin nav paths (#69969)
adding profile icon for non-admin nav paths
2026-03-03 14:30:32 -05:00
Alex Yarosh
b6b44f3cd6 docs: transform screenshots (#70225)
* transform updates

* more transform

* Optimized 11 images, saved 1015.9 KB (45.3% smaller)

* screenshot typo

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-03-03 14:19:42 -05:00
Jeff Bruemmer
e586b78513 docs - embedded Metabot (#70275) 2026-03-03 18:44:55 +00:00
John Swanson
330fb2727e SSO users can reset password if provider disabled (#70219)
Previously, password-reset-disabled? blocked password reset for all
SSO users unconditionally (except Google when SSO was globally
disabled). After a license downgrade, EE SSO users were locked out —
they couldn't use SSO (no license) and couldn't reset their password
either.

Introduce sso-source-enabled? which checks whether a user's specific
SSO provider is currently active, using setting/get to respect the
:feature guards on EE settings. password-reset-disabled? now delegates
to this function, so password reset is only blocked when the provider
is actually usable.
2026-03-03 10:42:00 -08:00
Maksym Yakubych
ea89a862ec feat: improve mention menu in metabot (#69650) 2026-03-03 17:33:32 +00:00
Alex Yarosh
0e6915287b docs: start redirect (#70323)
start redirect
2026-03-03 12:25:40 -05:00
Jakub Chodorowicz
d0ffa5115d Gdgt 1801 visualization typescript conversions leafletmap.tsx (#70248) 2026-03-03 17:26:53 +01:00
dpsutton
86dcec8883 Set team.json and assign modules: (#70309)
team:

```javascript
    {
      "name": "Graphy",
      "label": ".Team/Graphy",
      "members": [
        "ranquild",    // alex p
        "romeovs",     // romeo
        "ericnormand", // eric
        "galdre",      // timothy
        "dpsutton",    // dan
        "escherize",   // bryan
        "bgrabow"      // ben
      ]
    }
```

Modules:
- analyze
- graph
- sync
- enterprise/dependencies
2026-03-03 09:45:28 -06:00
Rodrigo López Dato
b2c736e4ca Missing space + log4j capitalization (#70271)
* Missing space + log4j capitalization

* Don't make changes in autogenerated MD files
2026-03-03 11:56:20 -03:00
Dan Stone
4a3e155ac9 Reenable bigquery incremental test (#70252)
Was toggled off individually due to issues with write consistency:
https://github.com/metabase/metabase/pull/69753
2026-03-03 14:44:16 +00:00
Braden Shepherdson
0f687a4a6b [MBQL lib] Prefer calling exported versions of several lib.util fns (#70269)
Fixes QUE2-352.

- `lib.util/strip-id` is newly exported with the more self-documenting
  name `lib/display-name-without-id`.
- `lib.util/clause?` and `clause-of-type?` were already exported
- `lib.util/source-card-id` (and `source-table-id`) are exported as
  `lib/primary-source-card-id` (and likewise for tables).

This isn't all the escaped usages of `lib.util` functions, but other PRs
will handle those.
2026-03-03 09:25:08 -05:00
Jakub Chodorowicz
5274ca8dcb Remove obsolete LeafletHeatMap and leaflet.heat (#70301) 2026-03-03 15:18:29 +01:00
github-automation-metabase
e0123c6246 Auto-update documentation for master (#70289)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-03-03 09:03:48 -05:00
Anderson
4301a00c1b Add snowplow events when creating measures and segments (#70218)
* Add snowplow events when creating measures

* Track also from the table measures page

* Add tracking events when creating segments

* Fix e2e
2026-03-03 13:47:37 +00:00
Kamil Mielnik
7dc0929cc1 GDGT-1834 Visualization Typescript Conversions - lib/settings/ (#69893) 2026-03-03 19:39:50 +07:00
Nicolò Pretto
cf40c24b36 set fail-fast to false in sdk host/sample apps tests (#70260)
disable fail-fast on sdk tests
2026-03-03 09:20:37 +01:00
Uladzimir Havenchyk
5c4c8753d7 chore: convert viz tests and helpers to typescript (#70059)
* chore: convert viz tests to typescript

* convert more tests

* more tests

* more tests

* more tests

* use global helpers

* more tests

* more tests

* convert settings definition

* more files to typescript

* more files to typescript

* fixup

* fixup

* Update v59 sample Examples visualizations and dashboard. (#70075)

Adds Box Plot viz and a Scalar viz with conditional colors to the Example dashboard.
The resources/sample-content.edn was regenerated from the live instance content.

* Pin patched libraries to their patched version (#70143)

* address review

* add a guard

---------

Co-authored-by: Katya Voropaieva <110612633+KorowkaMu@users.noreply.github.com>
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2026-03-03 11:14:29 +03:00
Anderson
d6540d2d62 Add snowplow events when creating a metric (#69990)
* Add snowplow events when creating a metric

* Fix tests in data-studio-metrics.cy.spec.ts

* Fix prettier
2026-03-03 01:09:31 -05:00
Nathan Voxland
d7f7d8285f Use the search cluster lock for both init indexing and re-indexing (#70272) 2026-03-02 18:07:55 -06:00
Jeff Bruemmer
cd68964a13 docs - fix summary formatting in users-roles-privileges.md (#70277)
Fix summary formatting in users-roles-privileges.md
2026-03-02 21:49:38 +00:00
Cam Saul
5e35a33837 Track whether column is :lib/from-model? (#70128)
* Track whether column is `:lib/from-model?`

* Additional fix 🔧

* Fix GH issue number

* (Try an evil hacc)

* Explain the HACC
2026-03-02 12:56:49 -08:00
Eric Normand
1734750c21 [Mutation Testing] Kill mutations in metabase.lib.field/fieldable-columns (#69321)
[Mutation Testing] Add tests for metabase.lib.field/fieldable-columns
2026-03-02 13:56:24 -06:00
Fraser
bb7604b53e Convert hoc-utils to ts (#70046) 2026-03-03 08:53:39 +13:00
Fraser
ea43ff2816 Convert Legend components to TypeScript (DEV-1502) (#69427)
* Convert Legend components to TypeScript (DEV-1502)

Convert Legend, LegendItem, LegendItemDot, and LegendLayout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:53:24 +13:00
Alex Yarosh
e8c624b479 docs: update plans for writeable connection (#70264)
* 😑

* remove blockquotes

* Update docs/databases/users-roles-privileges.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-03-02 19:06:42 +00:00
metamben
97d10fee1c Preserve metadata edits for summary columns (#70235)
* Preserve metadata edits for summary columns

Closes QUE2-17
2026-03-02 21:50:22 +03:00
Stas Gavrylov
5c6250fe4d GDGT-1859: Fix enabling Advanced Transforms (#70183)
* GDGT-1859: Fix Python transforms not enabled after adding to the trial

* GDGT-1859: Add page refresh after enabling Advanced Transforms

* GDGT-1859: Update unit tests
2026-03-02 13:42:27 -05:00
Nicolò Pretto
21a620c6e8 fix stress tests for sdk component tests (#70253) 2026-03-02 17:30:51 +01:00
Braden Shepherdson
1e3b836a7b [MBQL lib] Improve the docstrings for lib.computed (#70207)
The high-level docs in this namespace were lacking, and I got asked for a tour of it, so I improved the docs as well.
2026-03-02 10:25:52 -05:00
Dan Stone
a6ae573321 Turn on snowflake/bq tests for transforms (#70199)
They seem to be working ok https://github.com/metabase/metabase/actions/runs/22575305288
2026-03-02 14:21:42 +00:00
Egor Grushin
14740891cd GDGT-1785 Load cards in batches in the Transform Inspector (#70129) 2026-03-02 11:54:30 +00:00
Uladzimir Havenchyk
908ca1a1d6 chore: split into components and hooks ClickMappings (#70097)
* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* add a missing import

* chore: split into components and hooks ClickMappings

* fix imports

* delete old file

* make hook code human readable
2026-03-02 12:11:53 +03:00
Oleksandr Solovyov
94309cd070 Add toggle to enable/disable the Metabot (#70111) 2026-03-02 10:38:59 +02:00
Romeo Van Snick
d54e6b64e2 Convert parameters to typescript (#70137)
* Convert parameters to TypeScript

* Fix types

* Fix types in normalizeValue

* Fix types in dashboard tests

* Fix more types

* Fix test

* Remove duplicate check

* Naming
2026-03-02 17:07:10 +11:00
metabase-bot[bot]
763d5e1777 [chore] Update E2E test timings with recent data (#70236)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-03-02 12:16:14 +13:00
Fraser
b746306e12 Convert VisualizationError utils to TypeScript (#69062)
* Convert VisualizationError utils to TypeScript

Closes DEV-1407

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-02 11:53:39 +13:00
Fraser
f0c90980ff Convert DefaultParametersSection to TypeScript (#69075)
* Convert DefaultParametersSection to TypeScript

Closes DEV-1420

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-02 11:53:21 +13:00
Egor Grushin
e53f226b40 GDGT-1852 fix ui issues in Data Summary tab in Transform Inspector (#70150)
* GDGT-1852 fix ui issues
2026-03-01 22:48:32 +00:00
Romeo Van Snick
40cbf2ffb5 Avoid updating url when navigating to query builder (#68982)
* Use Question.serializeCardForUrl for consistency

* Convert metabase/lib/card to typescript

* Remove broken createCard helper

* Fix types

* Remove unused parameter

* Remove entityId from cards

* Remove createCard tests

* Avoid renaming Card to CardObject for no reason

* Also allow serializing UnsavedCard

* Make options optional

* Simplify serializeCardForUrl

* Make serializeCardForUrl implementation match the Question.serializeCardForUrl implementation

* Use serializeCardForUrl from metabase/lib/card

* Use serializeCardForUrl from metabase/lib/card

* Use stable stringify for url hashes

* Remove unnecessary _serializeForUrl helper

* Correctly ignore possibly infinite type instantiations

* Fix unit tests

* Allow passing parameterValues

* Fix comparison

* Coerce values to undefined

* Update unit tests

* Remove duplicate key

* Make cards optional
2026-03-02 08:38:55 +11:00
Braden Shepherdson
55a0afbd2a [MBQL lib] Stop using ID-based refs for fields from joined cards (#70116)
Fixes QUE2-383.

Uses `:lib/card-id` in metadata to check if a column came from a card at any point.
If so, it should use a name-based `:field` ref rather than an ID-based one.
This makes the refs to joined columns consistent with those to main source columns,
based on whether the source is a table or card.
2026-02-28 20:10:19 +00:00
Robert Kosara
f759d9f473 Docs: Tenant attributes and collections improvements (#70179)
* Tenant attributes and collections improvements

First round of edits to add the ability to create tenant attributes using SSO.

* Revise tenant-specific access for non-admin internal users

* Edits based on Alberto's comments

* Move tenant claims info to claims section, link to it from attributes

* Apply suggestion from @alexyarosh

Co-authored-by: Alex Yarosh <alexandra@metabase.com>

* Moved tenant attribute logic and simplified sentence

* Fix a sentence, improve code example, and clean up permissions bullet points

---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-02-27 13:46:20 -08:00
Uladzimir Havenchyk
39951a570a chore: make entity copy modal generic (#70018)
* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* chore: make entity copy modal generic

* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* add a missing import

* type cleanup

* address review
2026-02-28 00:07:56 +03:00
Alex Yarosh
6b369ef818 docs: writeable connection (#70210)
* writeable connection

* Optimized 1 images, saved 89.0 KB (46.9% smaller)

* routing notes

* typos

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-02-27 14:33:37 -05:00
Nemanja Glumac
f3c352d920 Increase viewport to reduce "extract column" flakes (#70206) 2026-02-27 20:06:00 +01:00
Anderson
9c0576cc5c Add snowplow event for opening Data Studio (#69880)
* Add snowplow event for when opening Data Studio

* Update triggered_from
2026-02-27 18:21:02 +00:00
Nemanja Glumac
fc00027fca Migrate away from deprecated Cypress.env() API (#70189)
As of Cypress 15.10.0, `Cypress.env()` is deprecated. This commit migrates
all usages to the new recommended APIs:

- Non-sensitive config values → `Cypress.expose()` (synchronous)
- Sensitive token values → `cy.env()` (asynchronous)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-27 19:03:29 +01:00
Nathan Voxland
6ca5625902 Code improvements 2026-02-27 12:47:50 -05:00
Ngoc Khuat
3be69174e6 Improve logging around notifications (#70099) 2026-02-27 16:55:43 +00:00
Nicola Mometto
11a73d8621 Add position field to dashboard parameters for stable serialization (#70107)
* revert sorting by id on parameters serialization, parameters ordering is significant and must be preserved

* revert, we're storing position

* feat: add :position to parameters, backfill

* feat: backfill position on imported parameters

* chore: tests

* FE: update position

* chore: gitignore python-sources.lock

* chore: ensure we get position

* restrict to dashboard params

* tests

* simpler approach: just sort by position on serialization export/import
2026-02-27 16:06:32 +00:00
Dan Stone
d1e7b483dd Prefer SQL DML for insert-from-source! to fix bigquery metadata consistency (#69753)
The legacy .insertAll API (and newer Storage API) do not work well with
tables that are created/dropped frequently. This is because their
metadata caches can take a long time to up date.

Python transforms use the drop-recreate fallback strategy for bigquery
so we observe this inconsistency for every run after the first, even
with absurd multi minute timeouts.

The SQL API does not have a problem, so we'll use that. We expect a
performance regression but its better to work slowly than not work at
all.

Other changes:

- Removed now redundant bigquery retry loop

- Dropped dictionary support, we cannot support it easily and it cannot be
considered higher prio than bigquery working at all.

- Added correct parameter typing for JSON.

- Fixed ordering issues in tests (assumed row order when it is
non-deterministic)
2026-02-27 15:47:58 +00:00
Ngoc Khuat
aa66ab25d6 Simplify notification result data flow (#70115) 2026-02-27 21:58:54 +07:00
Edward Paget
8207fc3181 feat: error code on streaming response throw/fail (#62351)
* fix: real error codes in streaming responses

* fixup! try faking old errors deeper in the stack

* fixup! wrap fetch endpoint in embedding too

* fixup! treat string only errors differently

* fixup! handle errors in a couple other places

* fixup! hard to figure out what kind of error it is

* fixup! typecasts

* fixup! test arity

* fixup! remove blanket 403 page from dataset

* fixup! simplify backend 403 responses

* fixup! a couple missed tests

* fixup! add mockresponse for mockclient

* fixup! other failing tests

* fixup! last failing test

* fixup! add another OSS check

* fixup! one more oss test

* fixup! update status codes on some more tests

* fixup! use committed function
2026-02-27 09:42:20 -05:00
Nicolò Pretto
b429839f0a remove sdk import error on core app e2e tests (#70188)
try to untangle imports
2026-02-27 14:41:19 +01:00
Jakub Chodorowicz
451f080ede add new variants to action icon and use it in Inspector Header cell (#70180)
* add new variants to action icon and use it in Inspector Header cell

* add is-active state
2026-02-27 12:10:07 +01:00
Dan Stone
4f00289729 Fix bigquery routing test (#70154)
- Was using wrong project / creds
- Using two different sha names only worked when shas were not used as
qualifiers in the query (they are for bigquery)

Added the ability to override the hash-key used for tx/hash-dataset to
support forcing a hash collision (as is required by routing).
2026-02-27 10:58:14 +00:00
Maksym Yakubych
369d410d4d fix: new SQL questions automatically open DataReference sidebar (#70120) 2026-02-26 21:09:43 +00:00
Nicola Mometto
b8c13482df fix: replace usage of source-table-id with primary-source-table-id (#70162) 2026-02-26 14:24:20 -05:00
Sloan Sparger
126eb6b1b1 [Metabot] Prevent OSS SQL gen UI from showing in cloud migrated instances (#69649)
prevent oss sql gen ui from showing for customsers with had set it up locally and migrated to cloud
2026-02-26 12:54:41 -06:00
Noah Moss
4ab19dce4d Ring middleware for public sharing endpoints (#70153)
* Ring middleware for public sharing endpoints

* Refactor test

* move +public-sharing-enabled to address module lint

* Fix documents test
2026-02-26 12:59:54 -05:00
Braden Shepherdson
39b4a21830 [MBQL lib] Refactor a common pattern into new lib functions (#68474)
Many uses of `lib.util/source-card-id` and `source-table-id` were
followed by calling `lib.metadata/card` or `lib.metadata/table`
respectively.

This PR adds two new functions `lib.metadata.calculation/primary-source-card`
and `primary-source-table` which look up the card/table directly.

It also adds `lib.metadata.calculation/primary-source` for the handful
of places where whichever of `primary-source-card` or `primary-source-table`
returns non-nil gets used, such as in some drill-thrus.
2026-02-26 17:32:57 +00:00
Eric Normand
3ba0f90cf0 Automate mutation testing end-to-end with run! orchestrator (#70126)
- Adds a fully automated `run!` entry point to `dev.mutation-testing` that orchestrates the entire mutation testing workflow: generate report → create Linear project → group functions → write tests via `claude -p` → verify → retry →
  commit → create draft PRs
  - Replaces the previous manual, step-by-step SKILL.md instructions (which required the operator to execute each step) with Clojure functions that handle the full pipeline automatically
  - Key new functions: `parse-namespace`, `group-functions`, `build-test-prompt`, `invoke-claude!`, `verify-and-retry!`, `process-group!`, `print-summary!`

  ## Motivation

  The mutation testing workflow previously required ~20 manual steps per namespace, with the Claude operator interpreting skill instructions and running each step. This was slow, error-prone, and required constant supervision. Now you just
  call `(mut-test/run! 'metabase.lib.order-by)` and walk away.

  ## How it works

  1. **`parse-namespace`** — derives source/test paths, short names, auto-detects `.cljc` vs `.clj`
  2. **`group-functions`** — clusters private functions with their public entry points based on test overlap, skips fully-covered functions
  3. **`build-test-prompt`** — assembles a prompt with function source, existing tests, and surviving mutations
  4. **`invoke-claude!`** — shells out to `claude -p` with scoped tool access (`Edit`, `Read`, `Bash(clj-nrepl-eval*)`)
  5. **`verify-and-retry!`** — checks which mutations were killed, retries up to 2x with targeted prompts for survivors
  6. **`process-group!`** — full per-group pipeline: branch → invoke Claude → verify → commit & push → Linear issue → draft PR
  7. **`run!`** — ties it all together, catches errors per group so one failure doesn't stop the batch
2026-02-26 09:51:59 -07:00
Nemanja Glumac
6e799b2ef6 Bump Cypress retries to two (#70157) 2026-02-26 17:42:51 +01:00
Dan Stone
dcd2d7394d Fix snowflake integer type (#70031)
BigInteger is observed
2026-02-26 16:04:33 +00:00
Aleksandr Lesnenko
3c693179e4 fix content translations break visualization settings (#70054)
* fix content translation produces unstable translated keys in viz settings
2026-02-26 10:54:11 -05:00
Braden Shepherdson
b01732fd69 [perf] Tools to repro query + metadata locally, given instance API access (#67952)
Given browser or API access to a Metabase instance, the tools in this PR
can recursively fetch cards and all the metadata (tables, fields, etc.)
required to run them through QP preprocessing and compilation.

Of course this cannot actually _execute_ the compiled form, since you
don't have access to the user's DWH, but it enables debugging of
hard-to-reproduce user bug reports in your local REPL.

This works by making API calls like `/api/card` and
`/api/card/query_metadata` until a complete picture of the metadata is
acquired. This is poured into a `MetadataProvider`, which is all the QP
needs to analyze and compile the query.
2026-02-26 15:49:56 +00:00
Nicola Mometto
a75ee49fd1 restrict a transform inspector test to sql (#70152)
fix: restrict to sql drivers
2026-02-26 15:23:21 +00:00
Eric Normand
dbfe313b4a Filter transforms based on permissions GHY-3152 (#70125)
Filter transforms based on permissions

We were leaking transforms in the :bad_transforms key
2026-02-26 14:55:12 +00:00
github-automation-metabase
088bd180d5 Auto-update documentation for master (#70133)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-26 09:46:51 -05:00
metabase-bot[bot]
0226eaa5d2 [chore] Update E2E test timings with recent data (#69996)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-26 15:04:49 +01:00
Nicola Mometto
3d68aa1ac4 feat: restrict join-analysis to only table-level join analysis (#70105) 2026-02-26 13:08:34 +00:00
Nemanja Glumac
c18c08b02c Pin patched libraries to their patched version (#70143) 2026-02-26 13:02:41 +01:00
Katya Voropaieva
851bedf5bb Update v59 sample Examples visualizations and dashboard. (#70075)
Adds Box Plot viz and a Scalar viz with conditional colors to the Example dashboard.
The resources/sample-content.edn was regenerated from the live instance content.
2026-02-26 10:45:57 +01:00
Uladzimir Havenchyk
9981cd5323 chore: convert dashboard reducer to typescript and rtk (#69842)
* chore: convert dashboard reducer to typescript

* convert to rtk

* use immer when possible

* fixup

* Apply suggestion from @kamilmielnik

I checked it locally and it is indeed unnecessary guard

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>

---------

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
2026-02-26 11:47:52 +03:00
Uladzimir Havenchyk
264604b61e chore: convert dashcard mapping files to ts (#69836) 2026-02-26 10:30:10 +03:00
Sébastien
a5a0773eaf Migrate ChartTypeDropdown to use Mantine ComboBox (#69734)
* Migrate ChartTypeDropdown to use Mantine ComboBox

* test fixes

* .

* .

* .

* .

* screenshot
2026-02-26 10:56:02 +07:00
Romeo Van Snick
c463756c60 Remove deprecated unit test helpers (#69275)
* Replace createQueryWithClauses with createTestQuery

# Conflicts:
#	frontend/src/metabase-lib/test-helpers.ts
#	frontend/src/metabase/querying/filters/hooks/use-date-filter/use-date-filter.unit.spec.ts

* Remove unnused helpers

# Conflicts:
#	frontend/src/metabase-lib/test-helpers.ts

* WIP

* Export createMetadataProvider

* Use Lib.createTestHelper

* Remove createQuery helper usage

* Remove createQuery helper

* Remove unneeded getJoinQueryHelpers

* Fix test

* Remove DEFAULT_QUERY

* Move or remove unneeded test helpers

* Fix lint

* Allow auto binning in test spec

* Fix test

* Allow disamiguating column name by index

* Fix tests

* Fix imports
2026-02-26 13:09:27 +11:00
Romeo Van Snick
0f7e8983ca Metakey helper (#68987)
* Use H.metaKey where applicable

* Add helper for meta key options

* Fix import

* Update more instances

* Fix test
2026-02-26 00:51:03 +00:00
Sloan Sparger
3401c9e902 Fix e2e dashboard-questions.cy.spec.js scrollTo flakes (#70114)
* invert assertions about scrollTo hash param and instead assert on visibility

* update e2e/test/scenarios/question/saved.cy.spec.js

* try to improve flakiness

* trying something dumb
2026-02-25 16:22:00 -06:00
Eric Normand
0aeda87a3d [Mutation Testing] Kill mutations in metabase.lib.field/fingerprint-based-default-unit (#69319)
Part of the mutation testing project for metabase.lib.field.

Closes QUE2-338

Functions
Stats
Surviving mutations before: 16
Tests added: 1
Mutations killed by this PR: 16
Mutations remaining: 0
Mutations killed
Replace fingerprint with nil
Replace :type with :type__
Replace :type/DateTime with :DateTime__
Replace let with comment
Replace earliest with nil
Replace latest with nil
Replace when-not with when
Replace days with nil
Replace > with >=
Replace > with nil
Replace days with nil
Replace 1 with 0
Replace :minute with :minute__
Replace 31 with 0
Replace 365 with 0
Replace :week with :week__
Mutations not killed (with rationale)
Replace :day with :day__ — available-temporal-buckets-for-type has its own internal default of :day for datetime types, so the :day return value from fingerprint-based-default-unit is redundant with the fallback
2026-02-25 22:07:25 +00:00
metamben
b1ece80c0d Support DB-local settings in the JVM and JS metadata-providers (#70117)
Closes QUE2-292
2026-02-25 21:52:17 +00:00
metamben
486a6fc826 Add test to prove that #35842 has been fixed (#70080)
Closes #35842
2026-02-25 21:25:19 +00:00
Eric Normand
29f75c1251 test: mutation tests for column-metadata-effective-type and nest-display-name (#69328)
* [Mutation Testing] Add tests for metabase.lib.field/fieldable-columns

* test: add mutation tests for column-metadata-effective-type and nest-display-name

Adds tests that exercise:
- type-of fallback to :base-type when :effective-type is absent
- type-of preference for :effective-type over :base-type
- temporal extraction returning :type/Integer
- temporal truncation preserving effective type
- nested field with nil parent display-name graceful fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:03:39 +00:00
metamben
66dc6b6cdc Add test to prove that #57978 has been fixed (#70076)
Closes #57978
2026-02-25 23:37:16 +03:00
metamben
7433f38a22 Make visible-columns for cards respect field visibility (#70040)
Closes QUE2-5
2026-02-25 23:36:59 +03:00
Cam Saul
71606de98c Test to prove #28060 is fixed 🔧 (#69865)
* Test to prove #28060 is fixed 🔧

* Update src/metabase/driver/mysql.clj

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>

* Update src/metabase/driver/mysql.clj

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>

* Fix syntax error from PR feedback suggestion

* Test fix 🔧

* Fix 🔧

---------

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2026-02-25 17:25:35 +00:00
Braden Shepherdson
d2e8fcac5b [MBQL lib] Export some healthy API functions; drop some API nses (#69666)
Fixes QUE2-350.

There are two changes here:
- Exporting some legit public functions from `lib.core`
- "Befriending" the `enterprise/sandbox` and `lib-be` modules, which are
  deeply coupled to lib and MBQL in any case.

That allows us to remove several exported namespaces:
- `lib.binning`
- `lib.convert`
- `lib.field`
- `lib.metadata.cached-provider`
- `lib.metadata.column`
- `lib.metadata.invocation-tracker`
- `lib.metadata.result-metadata`
- `lib.normalize`
- `lib.query`
- `lib.temporal-bucket`
- `lib.walk`

The functions newly exported from `lib.core` are:

- `lib.field/infer-has-field-values`, called from some BE API handlers
  and AppDB readers, producing a "cooked" value the FE wants rather than
  exposing details of how `:model/FieldValues` is stored. Single-use,
  but a legitimate export.
- `lib.field/json-field?`, checks if the passed in field is a JSON field,
  that's a valid export used in a few places.
- `lib.query/native?`, checks if the first stage of this query is native,
  that's another legit export used in a few places.

`lib.normalize/normalize` and `lib.query/query` were already exported, I
updated some usages of those functions to `lib/foo` instead.
2026-02-25 10:37:07 -05:00
github-automation-metabase
e4d1706837 Auto-update documentation for master (#70096)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-25 10:14:22 -05:00
Uladzimir Havenchyk
cc1361936a convert dashboard redux related files to typescript (#69797)
* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* add a missing import

* cleanup
2026-02-25 17:40:38 +03:00
Nemanja Glumac
69c0a2ca90 Upgrade Cypress to v15.10.0 (#69839) 2026-02-25 15:14:45 +01:00
Ngoc Khuat
3d3bbe22db Move pulse preview endpoints to dev-only (#70068) 2026-02-25 11:15:00 +00:00
Romeo Van Snick
ba0ddc9a32 Only switch to full-width native preview at small breakpoint (#70048)
* Only switch to full-width native preview at small breakpoint

* Add e2e test for metabase#67767
2026-02-25 20:22:46 +11:00
Fraser
da223ea0a1 Updated Chromium to v144 in Cypress (#69721)
* Bump chrome to v144
2026-02-25 21:07:41 +13:00
Noah Moss
f53c8d1513 Always run Metabot-triggered refingerprinting in admin context to match sync behavior (#70087)
* always run fingerprinting in admin perms context

* address comment
2026-02-24 17:47:22 -05:00
Fraser
51d7669d7d Convert admin/permissions/utils/urls to TypeScript (#69432)
* Convert `admin/permissions/utils/urls` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1510

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* improve type guard

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Uladzimir Havenchyk <uladzimir@metabase.com>
2026-02-25 10:18:09 +13:00
Anton Kostenko
eb20991259 Fix PR envs cleaning (#70024)
* Fix PR envs cleaning

* Add manual dispatch for pr env destroy
2026-02-24 15:16:50 -05:00
Nicolò Pretto
ec4874cfe5 re-generate lock file to remove stale deps (#70062)
* re-generate lock file to remove stale deps

* add sample apps to the deps for the package
2026-02-24 19:02:35 +01:00
Ngoc Khuat
8f442ca39b Add diagnostic logging for duplicate alert investigation (#70020) 2026-02-24 17:20:02 +00:00
Nicola Mometto
8c6e4aa60b Ensure we can resolve map lookups (#70060)
* feat: explicit handlebars context

* chore: unit tests
2026-02-24 13:53:19 +00:00
Nemanja Glumac
3d3d49dfca Automate Crowdin context harvester and trigger pre-translation (#70035) 2026-02-24 11:11:15 +01:00
Nicolò Pretto
bba60088cb emb-1300: use plugin for handleLink in eajs and fix double sdk plugin init (#69961)
* emb-1300: use plugin for handleLink in eajs and fix double sdk plugin init

* typo and fix unit test

* restore old comment
2026-02-24 09:25:38 +01:00
metamben
981113ef47 Use lib namespace on properties instead of real namespace names (#69808)
* Use lib namespace on properties instead of real namespace names

Closes QUE2-279
2026-02-23 22:53:37 +00:00
Braden Shepherdson
9c8e505c9f [QP] Move logging-only work inside the log/* call (#68362)
Move some logging-only computations into the `(log/* ...)` call so it won't be executed
unless the log level is sufficiently verbose for the log to actually be output.
2026-02-23 16:19:03 -05:00
Noah Moss
f4bbf2984f Add some better defaults & limits to agent API (#70033) 2026-02-23 15:35:18 -05:00
metamben
273f1677a1 Add tests for calculated display_name and fix nested name handling (#69982)
Closes QUE2-288
2026-02-23 23:23:58 +03:00
metamben
12e6b46118 Support all kinds of identity types on sqlserver (#69871)
Closes QUE2-251
2026-02-23 23:23:17 +03:00
Fraser
f27597b904 Convert AddEditSidebar to TypeScript (#69421)
* Convert AddEditSidebar to TypeScript (DEV-1499)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 08:45:56 +13:00
bryan
b2889824b3 Fix flaky count-of-grouping-test for Redshift by using UTC timezone (#67196)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-23 19:18:07 +00:00
Jeff Bruemmer
28cfae2e67 docs - table variables and snippets (#69983)
table variables and snippets
2026-02-23 11:34:02 -05:00
github-automation-metabase
60707e20ec Auto-update documentation for master (#70009)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-23 11:21:09 -05:00
bryan
a4e418f280 Fix OpenAPI 3.1.0 validation errors and add CI workflow (#69948) 2026-02-23 09:13:33 -07:00
Stas Gavrylov
c20bf2a943 GDGT-1755: Migrate common components to TypeScript (partial) (#69354)
* GDGT-1755: Migrate Text to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate Label to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate Subhead to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate IconWrapper to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate LabelIcon to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate use-scroll-on-mount to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Missed TS fixes

* GDGT-1755: Migrate QueryButton to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate IconBorder to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Remove Text.tsx wrapper, import from metabase/ui directly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Adjust line height in places using new Text component

* GDGT-1755: Fix styling inconsistencies

* Update frontend Claude guidelines for typecheck/linting to use bun

* GDGT-1755: Address PR comments

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 18:13:01 +02:00
Alexander Polyankin
c66d31fec1 Drop table created in a e2e test (#70023)
* drop table created in a e2e test

* fix
2026-02-23 10:43:37 -05:00
Egor Grushin
93cb3bc327 lock a card display type for the VisualizationCard (#70016)
lock a card display type for the VisualizationCard in the transform inspector
2026-02-23 14:55:23 +00:00
Timothy S. Dean
52325a7503 Write Connections for Actions, Model Persistence, Uploads (#69878) 2026-02-23 09:15:35 -05:00
Fraser
dadf042982 Convert ExpandableString to TypeScript (#69084)
Closes DEV-1429

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 15:49:29 +02:00
Dan Stone
18e1fb02aa Revert turning on snowflake/bq tests for transform (#70017)
Revert "Re-enable Python transform tests for BigQuery and Snowflake (#67685)"

This reverts commit b6c1a51630.
2026-02-23 12:41:22 +00:00
Egor Grushin
5dd8b26770 getting rid of annoying warnings (#69975) 2026-02-23 12:17:08 +00:00
Dan Stone
b6c1a51630 Re-enable Python transform tests for BigQuery and Snowflake (#67685)
These tests were temporarily disabled on 2025-09-26 due to flakes.
Re-enabling them now to restore full test coverage.

Lets monitor and see what happens
2026-02-23 10:38:56 +00:00
Nicola Mometto
09ee4178ca Transforms inspector (#68675)
* wip: transform inspector BE

* WIP: inspect tables

* wip

* format join info as code

* wip: join info

* style

* add join stats type and display match rate

* chore: row

* chore: remove limit

* wip

* handle differerent cases for match rate and row count

* add joins table display and icons

* fix copy

* fix missing join table names

* cleanup

* cleanup

* extend match

* fix missing source table type

* add join tooltip

* chore: with join info

* wip

* wip

* add field statistics dummy component

* small ui adjustments

* small ui adjustments

* add filled rows

* order input columns like joins

* update visualization card styling

* wip: update join calc to be iterative

* add target and source stats

* add target and source stats, a filter by output fields and a tab for unmapped fields

* add target and source stats, a filter by output fields and a tab for unmapped fields

* chore: sort by order

* fix: inverse map

* add cross product warning

* add null join warning

* small QoL UI improvements

* wip: render output_row_count

* wip: native joins

* fix a bug with conditional rendering

* wip: try to pull out useful fields

* WIP: claude'd UI selection of visited_fields

* use default automatic display selection logic

* add transform mock page with mock summary section

* add mock api console log

* fix fetch wrong query metadata

* add mock lenses

* add mock lenses api

* REVERTME: ignore for deploy

* feat: schemas

* require

* feat: degeneracy check

* WIP cljc api

* wip context

* wip lenses

* update comments

* chore: visited-fields

* wip

* wip: base

* wip: triggered lens

* wip: lib

* distinguish drill lenses

* fix: return visited-fields

* wip: v2 api

* WIP: vibe'd FE

* tabs/remove mock

* account for params

* params

* ui improvements

* fix

* show fingerprinting

* fingerprint layout

* use BE fallback

* handle more complex joins

* fallback to interesting fields

* fix trigger via cljc

* remove debug

* different text

* compute-card-results in cljs

* condition trigger in cljc

* semi working

* fix card_id correlation

* remove dead code

* rename BE to just inspector

* switch to new

* ensure transform is deleted

* chore: cleanup schema

* bring back the field fingerprint info

* move cljs out of lib

* fix: schema

* minor cleanup

* appease kondo

* kondo

* remove dead code

* feat: centralize native analysis in query_analisis

* chore: remove #p

* clean up

* Gdgt 1663 move fingerprints out of the lens to data inspect (#68996)

* [transforms inspector] depend on trunk macaw (#69022)

depend on trunk macaw

* fix lint and type issues (#69017)

* remove unused lib function

* fix infinite rendering loop

* fix type lib.interestingFields

* fix

* fix: ui bug

* chore: disable visited fields for now

* chore: better unmatched-rows

* chore: exclude not nulls

* minor tweaks

* minor tweaks

* rename

* chore: tighter contract

* minor optimisation

* Gdgt 1669 make cards clickable (#69116)

* Add card link

* link to hash of question

* add clickable title

* remove tooltip

* Use MBQL info to match columns whe npossible (#69120)

use mbql info for column matching

* Gdgt 1675 disable unmatched rows view details button in inspector (#69152)

* remove row index column

* adapt viz UI, hide row index column

* Unmatched rows lens: return cards for both LHS or RHS null scenarios (#69123)

* feat: handle both cases of no join match

* feat: simple degeneracy

* export function

* remove dead fields

* only propose drill lenses that are applicable (#69169)

* Transforms inspector consistent casing for FE (#69174)

* chore: consistency

* chore: some docstrings updats

* feat: snake_case for the FE

* feat: pass visitedFields to interestingFields, remove ad-hoc logic in FE (#69175)

feat: pass visitedFields to interestingFields, remove ad-hoc logic in the FE

* feat: namespace card-ids with params (#69180)

* add estimated lens complexity (hardcoded for now)  (#69181)

* add estimated lens complexity (hardcoded for now)

* refactor: use with-metadata

* add metadata to triggers, not just cards (#69182)

* appease kondo

* chore: don't depend on git sha macaw

* reinstate metabase-enterprise.transforms.core from merge conflict

* Gdgt 1722 new UI for data summary new (#69220)

* Transforms inspector BE tests  (#69225)

* feat: inspector tests

* fix: impls

* fix: nil safe

* feat: integration tests

* make it work for both FE and BE

* fix card-results for non oute rjoin

* e2e test

* fixes

* fix: quoting

* fix for mysql/bigquery/redshift

* gdgt-1721 rework lenses navigation (#69205)

* Transforms inspector module (#69278)

* split transforms inspector into its own module, introduce transforms-rest

* handle kondo modules warnings

* fix: shadow_cljs

* kondo: fixes

* Transforms inspector be review (#69339)

* chore: align

* remove useless comments

* feat: add schema to context

* feat: simplify column-matching

* fix: visited-fields

* fix test

* remove unused

* tighter schema

* extrac-sources test

* fix: missing metadata-provider

* Gdgt 1744 combine separate averages columns into one for data summary (#69355)

* gdgt-1723 New UI for Joins Analysis (#69325)

* Gdgt 1725 allow running transform from empty screen (#69394)

* chore: move crud functions on transforms, avoid -rest modules dependencies

* fix tests

* appease kondo

* fix modules

* fix: small UI bug

* Transforms orphaned columns (#69497)

* add orphaned columns to unmatched-rows analysis

* chore: update tests

* Transforms inspector analytics (#69484)

* feat: flow discover/lens through transform events

* track transform_id in query execution

* feat: add transform-inspector ids/params to query info

* feat: add inspector specific /query endpoint

* feat: hook FE to new api

* feat: add lens_id/params to view

* feat: add them to ua

* fix: pass params too

* fix: use text.type

* fix test

* chore: remove unused requires

* chore: events

* fix FE part

---------

Co-authored-by: Egor Grushin <egor@metabase.com>

* fix: use lib functions instead of manual mbql construction (#69519)

* fix: use lib functions instead of manual mbql construction

* chore: refactor utils

* cleanup

* more manipulation with lib

* bugfix

* strip fields/filters early

* do it in util function

* fix: bad merge resolution

* kondo

* another bad merge resolution

* chore: indent

* Gdgt 1754 handle slow loading lens indicator (#69334)

* lens loading indicator

# Conflicts:
#	frontend/src/metabase/transforms/pages/TransformInspectPage/TransformInspectPage.tsx
#	frontend/src/metabase/transforms/pages/TransformInspectPage/components/LensContent/LensContent.tsx

* add onCardLoaded handler to context

* Gdgt 1724 new UI column (#69282)

* Gdgt 1783 fix wrong args passed to lens query (#69546)

* fix wrong args being passed to lens queries

* improve naming of query parameters

* remove whitespaces from merge resolution

* add transforms api test

* feat: i18n the inspector strings (#69565)

* fix dark mode color issues (#69570)

fix bg fixed to white

* Gdgt 1737 use card metadata instead of parsing card ids (#69583)

* use card metadata instead of parsing ids

* improve way of getting the table name from cards

* use macaw still, TODO

* port some query-analysis to sql-tools (#69732)

* chore: port some query-analysis to sql-tools

* remove sql-tools from transforms

* chore: vendor macaw functions, appease kondo

* refactor

* chore: refactor

* side agnostic

* revert manual delete, closes https://linear.app/metabase/issue/GDGT-1730/pre-merge-blocker-revert-t2delete-on-transform-once-uxw-3021-is-fixed

* fix: always sync audit db on change

* dead code

* fix: use honeysql instead of building sql manually (#69774)

* GDGT-1791 Maximum depth error in console (#69754)

GDGT-1791 fix and refactor useCardLoadingTracker

* Gdgt 1651 add frontend e2e tests for transform inspector UI (#69677)

* GDGT-1823 make guarantee that LensContent is always stores one lens data (#69800)

* fix: 404 on lens not found (#69838)

* fix: 404 on lens not found

* chore: don't pmap

* fix: remove nil values from statistics

* fix

* Transforms inspector self review be (#69843)

* style

* chore: reuse resolve-join-sides

* add from-table-id for mbql queries too

* split context in mbql/native, don't union

* whitespace

* fix: preprocess native queries

* fix: update tests

* fix

* revert unrelated commit that made in the branch erroneously

* Gdgt 1812 better handle missing sources in lens inspector (#69848)

* Gdgt 1817 add snowplow product events fe (#69801)

* Add analytics events

# Conflicts:
#	frontend/src/metabase/transforms/analytics.ts

* add analytics tests

* simplify and improve lens loaded tracking event

* Move the idempotence check to useLensLoadedTracking

* GDGT-1831 replace unstyled button with a box to get rid of button in button error

* chore: transform lens_params

* GDGT-1786: Parametric lens navigation improvement (#69821)

* GDGT-1757: Refactor Column Comparison utils grouping and scoring logic (#69853)

* Improve types with entity ids (#69891)

* add concrete type declarations and usage for InspectorLensId, InspectorCardId, InspectorSectionId

* add better type to lens params

* cleanup of utils

* improve type for displaySettings

* use entity aliases in more places

* use existing type aliases for source and target

* add comment about InspectorTriggerCondition type

* unify prefix for inspector types

* remove spurious catch

* deduplicate types between metabase-api and lib

* Remove unused query

* fix provided tags for transform inspector

* add alerts and drill buttons test for default lens sections (#69899)

* restrict join analysis to single condition joins

* fix: bad merge reoslution

* fix types in lens test

* use isa function to detect type

* use concrete table id type alias

* use Urls.openInNewTab util

* remove empty mocks file

* use concrete table id type

* move lib for transform inspector to src/transforms/lib

* remove superflous log in e2e tests

* add proper SchemaName type

* remove superflous export

* revert move of isFetchBaseQueryError

* remove obsolete test

* use correct SchemaName type alias

* use correct VisualizationDisplay type

* remove leftover unused type

* remove superflous export

* Use CardId type alias

* discern lens also by based on params when tracking loading

* GDGT-1839 addressing the PR comments

* GDGT-1839 addressing the PR comments

* GDGT-1839 addressing the PR comments

* GDGT-1839 move getLensKey and LensHandle from api/tags directory

---------

Co-authored-by: Egor Grushin <egor@metabase.com>
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
Co-authored-by: Jakub Chodorowicz <jakub@chodorowicz.com>
2026-02-23 10:16:35 +00:00
Ngoc Khuat
a68b644ec8 Add prominent CTA button per failed transform in failure email (#69458) 2026-02-23 14:51:28 +07:00
Fraser
ca002fd953 Convert app-embed and app-public to TypeScript (#69438)
* Convert `app-embed` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1516

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 09:49:58 +13:00
Nathan Voxland
a4fdcdef64 Code review fixes 2026-02-21 10:21:20 -06:00
Nathan Voxland
b1fe71ca2f Cleaning up force-sync usage 2026-02-21 02:29:02 -06:00
Nathan Voxland
4daf2cb8a2 Added batch-listen! 2026-02-21 01:52:57 -06:00
Anderson
ba5de0f2fa Show Python upsell on self hosted (#69759)
* Show Python upsell on self hosted

* Add e2e tests

* Fix unit test

* Simplify TransformsUpsellPage a bit more, fix tests

* Simplify logic

* Fix e2e and unit test

* Update self-hosted python upsell as per new design / Code clean up

* Fix unit test and also add a new one for useTransformsBilling

* Remove e2e tests to be moved to a new PR

* Fix cta link and bullet points icon alignment
2026-02-20 22:42:10 +00:00
Nathan Voxland
b4f717609e Add support for OpenID Connect (#69538) 2026-02-20 16:18:58 -06:00
Nathan Voxland
4a3d739318 Started to migrate old util.queue code to new mq 2026-02-20 15:41:51 -06:00
Oleksandr Yakushev
3f898be45a [match] Implement replace-lite and use it instead of replace (#69270) 2026-02-20 23:39:57 +02:00
Edward Paget
071fc345b4 fix: better check for dirty collection state (#69974)
Our frontend code that prevents sending unchanged collections missed
tenant collections being added to the payload. This fixes both the
frontend to make sure we don't send when there are no changed
collections and it updates the backend actually check if collections are
being changed rather than just checking if the collections map exists.
2026-02-20 13:13:27 -06:00
Timofey Kachalov
08c4a89f91 fix(EmbedJS): Downloads fail on guest embedded questions (#69972) 2026-02-20 23:04:33 +04:00
Edward Paget
7d2d6571cb fix: transforms collections set setting on import (#69852)
* fix: transforms collections set setting on import

Also turns off the transforms sync setting if there are not transform
related models in the import

* fix: transform/snippet settings on collection sync

Updates our check for 'did transforms or snippets change on remote' to
examine collections in the respective namespaces so an import with only
transform collections (or snippet collection) creates the correct
settings on the importing instance.

* fixup! better handling for custom vs builtin tags

* fixup! better conflict checking of namespaced cols

* fixup! explicit connectionb for token cache

* fixup! PR feedback
2026-02-20 10:54:57 -06:00
Ryan Laurie
f6f2a31b6a Enable automated patch releases (#69971)
enable automated patch releases
2026-02-20 16:26:26 +00:00
github-automation-metabase
1342901722 Auto-update documentation for master (#69953)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-20 09:53:52 -05:00
Timofey Kachalov
a554da88bd Change the way of building the base_ref embedjs bundle (#69910) 2026-02-20 15:55:19 +04:00
Mahatthana (Kelvin) Nomsawadi
7fa10713ea Support passing dataPicker to SDK components to force staged data picker (#69631)
* Adding dataPicker to embedding-data-picker redux store

* Refactor: move `dataPicker` redux

Move from interactive embedding store to embedding data picker store

* Add `dataPicker` type for the SDK

* Fix storybook id value

* Accept `dataPicker` in modular embedding SDK

* Make the doc more suitable for markdown table in the docs site

* Add test for InteractiveQuestion

* Fix drillThroughQuestionProps type

* Add tests for drillThroughQuestionProps.dataPicker

* Fix SDK components can't specify different `entityTypes` or `dataPicker`

* Fix doc error

* Fix comment grammar

* Fix wrong file name

* Clarify redux slice usage with a comment

* Make context more specific to avoid misuse

* Add `question` back to SDK's `entityTypes` on the API doc
2026-02-20 11:27:46 +00:00
Nemanja Glumac
43e3fa694d Revert "Run container as non-root, simplify H2 handling in entrypoint (#64977)" (#69958)
This reverts commit 54bd11c5b9.
2026-02-20 10:42:48 +00:00
lbrdnk
370a4dff14 Enable check_snippet endpoint (#69892)
* Enable the check_snippet endpoint

* Param

* Test

* Test
2026-02-20 10:04:58 +01:00
Uladzimir Havenchyk
dc319ca76a feat(dashboard): move subscriptions to action menu (#64950)
* feat(dashboard): move subscriptions to action menu

* fix unit tests

* fix e2e tests

* fix console warning about uncontrolled component

* fix more tests

* fix remaining test

* bring test back
2026-02-20 08:39:55 +00:00
Romeo Van Snick
b08d62e316 Transforms with params UI (#69728)
* Validate transform queries can be preprocessed

* remove prn

* update backend error messages

* Add support for custom toggleTemplateTagEditor

* Allow passing setTemplateTagConfig to TagEditorParam

* Add support for storing parameter values when question changes

* Add template-tags tab

* Add template tag sidebar

* Allow saving optional template tags or tags with a default value

* Show error message on save

* Add new spec for transform template tags

* Avoid sharing state when navigating

* Add combination test for template tag types in transforms

* Add definitionTab helper

* Add test for multiple template tags

* Fix error message

* Fix tooltips in test

* Remove tooltip check in tests

* Use getErrorMessage to get error message in toast

* Only return message if it is not empty

* Wrap error message in form

* Use H.createTestNativeQuery helper

* Move variableTemplateTags and isVariableTemplateTag to Lib

* Use more conventional key to reset uistate

* update backend error messages again

* Revert "Wrap error message in form"

This is now handled in the api

This reverts commit 9efecaf261.

* Fix test

---------

Co-authored-by: William Zimrin <william@metabase.com>
2026-02-20 13:15:02 +11:00
Alexander Polyankin
ba302fc0ef Diagnostics cleanup pulled from the metrics branch (#69926) 2026-02-20 01:15:01 +00:00
Anderson
716a26ef75 Remove Exit sidebar menu item now that app switcher exists (#69886) 2026-02-19 23:53:20 +00:00
dpsutton
f1de74d0d2 [master] security fixes (#69924)
* security fixes

* Use actions dataset

Symptom:
We started having tests failing

like:

```
expected: {:has_more_values false,
           :values [["African"] ["American"] ["Artisan"]]}
  actual: {:has_more_values false, :values (("American") ("Artisan") ("Asian"))}
    diff: - {:values [["African"] ["American"] ["Artisan"]]}
          + {:values [["American"] ["Artisan"] ["Asian"]]}
```

and

```
expected: {:has_more_values true,
           :values [["African"] ["American"] ["Artisan"] ["Asian"] ["BBQ"]]}
  actual: {:has_more_values true,
           :values (("American")
                    ("Artisan")
                    ("Asian")
                    ("BBQ")
                    ("European Shop"))}
    diff: - {:values [["African"] ["American"] ["Artisan"] ["Asian"] ["BBQ"]]}
          + {:values [["American"]
                      ["Artisan"]
                      ["Asian"]
                      ["BBQ"]
                      ["European Shop"]]}
```

Identify:
```
modified   src/metabase/actions/execution.clj
@@ -35,6 +35,10 @@
                                                               [:model_id      ::lib.schema.id/card]
                                                               [:dataset_query ::lib.schema/native-only-query]]
    request-parameters]
+  (let [db-name (-> ((requiring-resolve 'metabase.test/db)) :name)]
+    (when-not (.startsWith db-name "actions-test-data")
+      (println clojure.test/*testing-vars*)
+      #_(clojure.repl/pst (Exception. "how here?") 500)))
   (log/tracef "Executing action\n\n%s" (u/pprint-to-str action))
   (try
     (let [parameters (for [parameter (:parameters action)]
@@ -61,6 +65,10 @@
 (defn- execute-custom-action! [action request-parameters]
   (let [{action-type :type} action]
     (actions/check-actions-enabled! action)
+    (let [db-name (-> ((requiring-resolve 'metabase.test/db)) :name)]
+      (when-not (.startsWith db-name "actions-test-data")
+        (println clojure.test/*testing-vars*)
+        #_(clojure.repl/pst (Exception. "how here?") 500)))
     (let [model (t2/select-one :model/Card :id (:model_id action))]
       (when (and (= action-type :query) (not= (:database_id model) (:database_id action)))
         ;; the above check checks the db of the model. We check the db of the query action here
@@ -165,8 +173,14 @@
   (let [k (keyword (:kind action-instance))]
     (legacy->current k k)))

+(require 'clojure.repl)
+
 (defn- execute-implicit-action!
   [action request-parameters]
+  (let [db-name (-> ((requiring-resolve 'metabase.test/db)) :name)]
+    (when-not (.startsWith db-name "actions-test-data")
+      (println clojure.test/*testing-vars*)
+      #_(clojure.repl/pst (Exception. "how here?") 500)))
   (let [model-id        (:model_id action)
         implicit-action (parse-implicit-action action)
         {:keys [query row-parameters]} (build-implicit-query action implicit-action request-parameters)
```

I modified the action execution to print out test vars that weren't
using the correct dataset. A few need cross datasets to ensure can't run
on different dbs, and a few don't matter because they assert that
permissions fail or data is missing. But this
execute-action-permission-test didn't, and it's last branch asserts
"Admin can still execute actions" and that seems to have been the cause
of our troubles
2026-02-19 15:16:26 -08:00
Nathan Voxland
ba85c0513c Cleanup failed queue messages 2026-02-19 16:55:00 -06:00
Nathan Voxland
b8c26e3c0c Code review fixes 2026-02-19 16:48:09 -06:00
Rodrigo López Dato
54bd11c5b9 Run container as non-root, simplify H2 handling in entrypoint (#64977)
* Run container as non-root, simplify H2 setup

* Permissions

* add to bin/Dockerfile

* Update Dockerfile

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>

* Update bin/docker/Dockerfile

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>

* bad bot :(

* docs

* bring back JAVA_TIMEZONE

* don't hardcode default h2 directory in command

* fix link

* update openapi

---------

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>
2026-02-19 19:25:16 -03:00
Nathan Voxland
21b5b3e93a Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	resources/migrations/059_update_migrations.yaml
2026-02-19 16:20:28 -06:00
Nemanja Glumac
2e3efef978 Use core.setFailed instead of throw for missing artifacts (#69897)
When an artifact doesn't exist (expected for new commits), the
fetch-artifact action was using throw new Error() which causes
GitHub Actions to report "Unhandled error" - confusing and noisy.

Using core.setFailed() cleanly marks the step as failed without
the scary error message.

Fixes: DEV-1581

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 23:15:33 +01:00
Nathan Voxland
0a1a13b48b Code cleanup 2026-02-19 16:09:11 -06:00
Nathan Voxland
a18f7a94e2 Code cleanup 2026-02-19 15:34:05 -06:00
Rodrigo López Dato
9d9433b5b0 docs: Fix step numbering + add details on how to confirm if using H2 (#69581)
* Fix step numbering + add details on how to confirm if using H2

* fix anchor links
2026-02-19 18:19:46 -03:00
Rodrigo López Dato
f56c4e39cb Mention that the appdb schema must always be public (#69905) 2026-02-19 18:19:16 -03:00
bryan
f3fa8226cf Add debug echo to driver-decisions CI step (#69881)
Prints the mage command and args before execution so we can quickly
see what labels/flags were passed when debugging CI driver issues.

Closes: DEV-1577
2026-02-19 21:10:20 +00:00
Rodrigo López Dato
4376ecc379 Update model index limit in docs (#69933) 2026-02-19 18:08:16 -03:00
Braden Shepherdson
2c04482d27 [MBQL lib] Move leaky column logic from models.interface into lib (#69665)
Fixes QUE2-353.

`mi/normalize-result-metadata-column` called some internals to modernize
a possibly-lib, possibly-legacy column from `:result_metadata` on a
card. Pull that logic into Lib as a new exported function.
2026-02-19 20:52:27 +00:00
bryan
be492dc637 Remove unused HTTP action code paths (#69764)
* Remove dead code for actions

* Disable HTTP action type at API level

* clarify thrown exceptions

* Remove HTTP action tests

HTTP actions are now blocked at the API level; these tests cover
functionality that's no longer accessible.

* Remove remaining HTTP action references from api_test

The previous commit missed several HTTP action usages:
- all-actions-default helper function
- list-actions-test action-1 binding
- action-parameters-test (now uses query action)
2026-02-19 20:07:24 +00:00
Anderson
b2fb97a98a Replace 'Set up git sync' with 'Set up remote sync' on Data Studio sidebar (#69883) 2026-02-19 19:11:52 +00:00
William
347f3f11b4 Transforms with parameters (#69592)
We want to support transforms with template tags, as long as those tags aren't required or have default values. However, if we do that, the backend should actually verify that we do in fact have values for all relevant template tags. This pr adds basic validation logic to transform creation and update routes -- essentially, we just run qp.preprocess/preprocess and see if we get an error.
2026-02-19 12:03:00 -06:00
Edward Paget
d59d58e61a Fix narrow symbol downloads with tests (#69811)
* Fix downloading currency values in narrowSymbol format (#69779)

* Add tests for narrowSymbol currency style in downloads

---------

Co-authored-by: Will Bryant <will.bryant@gmail.com>
2026-02-19 11:39:11 -06:00
Timofey Kachalov
c8d8369fec feat(embed-js): Add docs hint for additional wizard properties (#69906) 2026-02-19 21:14:10 +04:00
Nathan Voxland
067626c71d Added metrics 2026-02-19 10:41:42 -06:00
Sébastien
ecaff38ac0 improved doc generation for EAJS (#69890) 2026-02-19 17:30:20 +01:00
Nemanja Glumac
951f74665d Do not cache UV (#69902) 2026-02-19 17:18:14 +01:00
Dan Stone
acf4530cc6 Move transform metering back into EE module (#69840)
* Move transform metering back into EE module

The defenterprise shadowing was not working as the metering function was
moved

* Add test of EE stats
2026-02-19 16:05:06 +00:00
Nathan Voxland
3bc10ee2e1 Cleanly shut down 2026-02-19 09:53:39 -06:00
Rodrigo López Dato
8eccd8a0f9 Capitalize Jar -> JAR (#69900) 2026-02-19 11:26:31 -03:00
Nemanja Glumac
83fdafad01 Introduce Copilot code review instructions (#69846) 2026-02-19 11:14:54 +01:00
Nathan Voxland
b9fba6ab7a Cleaning up topic code 2026-02-19 01:15:32 -06:00
github-automation-metabase
71cfad67bb Auto-update documentation for master (#69888)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-18 20:43:17 -05:00
Fraser
103e9056e1 Convert QueryButton to TypeScript (#69419)
* Convert QueryButton to TypeScript (DEV-1497)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Tighten types
2026-02-19 14:15:56 +13:00
Cam Saul
984cf44eca More robust visualization settings normalization (#69860)
* More robust visualization settings normalization

* Remove stray `println`
2026-02-18 16:20:00 -08:00
Nathan Voxland
20e5611810 Cleaning up topic code 2026-02-18 16:26:15 -06:00
Jeff Bruemmer
d2f7234d7f docs - sql table variable (#69817) 2026-02-18 17:07:30 -05:00
Nathan Voxland
37d68bca75 Made mq.topic code look like mq.queue code 2026-02-18 15:52:48 -06:00
Nathan Voxland
e58e0b7f80 Queue code improvements 2026-02-18 15:21:22 -06:00
Timothy S. Dean
4ab6f9df02 Transforms DB Connection (#68883)
Problem: When a database is configured for both SQL access and Transforms, any feature with SQL access (like raw SQL questions) inherits the elevated permissions (CREATE, DROP, INSERT, etc.) that Transforms need.

Solution: Admins can _optionally_ configure write credentials alongside existing read credentials. One logical database, two connection types. Specific code paths opt in to using write credentials; by default everything uses a read-only connection.

How: This PR adds a new `write_data_details` column on `Database`. If `write_data_details` isn't configured, everything will still use `details` as before. When it is configured, it acts as a set of overrides on top of `details`, but only in code paths that require write permissions. There should be no behavioral change for existing deployments.
2026-02-18 13:57:16 -07:00
Edward Paget
4c0c9aa08f fix: log parameter not nil value (#68200) 2026-02-18 14:29:50 -06:00
Nathan Voxland
81aab7b8ca Added schemas 2026-02-18 14:15:45 -06:00
Nathan Voxland
bcf8a422f6 Queue code cleanup 2026-02-18 14:03:30 -06:00
Rodrigo López Dato
32a00c99e5 Explain how DB routing and query caching work together (#69855)
* Explain how DB routing and query caching work together

* Update docs/configuring-metabase/caching.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-18 19:38:19 +00:00
Nathan Voxland
ac434a50aa Queue code cleanup 2026-02-18 13:02:49 -06:00
github-automation-metabase
559c2f27de Auto-update documentation for master (#69833)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-18 11:44:49 -05:00
Nemanja Glumac
fd775c440d Split long running e2e specs into smaller chunks (#69844) 2026-02-18 17:18:36 +01:00
Nemanja Glumac
4a79872533 Clean up more unneeded dependency "resolutions" (#69837) 2026-02-18 17:14:53 +01:00
Timofey Kachalov
127132f8a6 Measure Embedding SDK Hosted Bundle bundle size (#69743) 2026-02-18 19:57:09 +04:00
Nathan Voxland
140d1adcb7 Remote-Sync: Support other git providers (#69675) 2026-02-18 09:37:25 -06:00
lbrdnk
639c8debc9 Enable native entity validation (#69784)
* Enable native entity validation

* Adjust tests

* Adjust test

* Adjuts tests

* Enable check_card and check_transform for native entities

* Adjust test to check child staleness

* Adjust test

* Adjust e2e test
2026-02-18 14:23:18 +01:00
Oleksandr Yakushev
795fa21b9d Add &parents to match-lite and rewrite remaining match/match-one usages (#69259) 2026-02-18 15:04:04 +02:00
lbrdnk
2f043ea9d2 Sqlglot review follow-up (#69788)
* Review remarks (incl. .sqlglot-version removal)

* Use uv.lock

* Restore batch-lookup-table-ids

* Adjust test

* Apply suggestions from code review

Co-authored-by: bryan <bryan.maass@gmail.com>

* Add sqlglot version parsing test

---------

Co-authored-by: bryan <bryan.maass@gmail.com>
2026-02-18 13:23:29 +01:00
Dan Stone
0e113a5c68 Accept string target :type in transform test helper (#69804)
It makes sense to use strings in http tests because that is what the
http-client will accept as json.

If a string target :type is supplied, we convert it to a keyword to
ensure we can dispatch to the intended method.
2026-02-18 11:06:04 +00:00
Nathan Voxland
4f050fba0a Use notify on postgres 2026-02-18 01:25:29 -06:00
Nathan Voxland
c36a72146e moved queue and pubsub to .mq 2026-02-18 00:27:53 -06:00
Uladzimir Havenchyk
e3ec99133a chore: convert IconBorder component to typescript (#69735)
* chore: convert IconBorder component to typescript

* pass rest parameters

* inline component

* fixup
2026-02-18 06:19:21 +00:00
Fraser
cd8c4b1e98 Convert lib/syncing to TypeScript (#69428)
* Convert `lib/syncing` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1507
2026-02-18 16:16:10 +13:00
Romeo Van Snick
ead4e7d4d9 Fix unreferenced dependency flakes (#69535)
* Scroll item into view

* Fix sidebar test

* Wait for page to be visible
2026-02-18 14:15:52 +11:00
Fraser
f3fe43bb86 Convert LoginHistory to TypeScript (#69412)
Convert LoginHistory to TypeScript (DEV-1491)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 14:36:39 +13:00
Fraser
e385103a21 Convert LimitPopover to TypeScript (#69076)
* Convert LimitPopover to TypeScript

Closes DEV-1421

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-18 14:10:11 +13:00
Nathan Voxland
13681a004a Improve event creation remote-sync (#69768) 2026-02-17 18:05:08 -06:00
Nathan Voxland
d82ec362ba Added pub/sub messaging 2026-02-17 17:04:11 -06:00
Fraser
a8715223ae Convert embedding/saved-entity-picker/utils to TypeScript (#69442)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1520

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:29:25 +13:00
Fraser
3cbf8919a7 Convert lib/string to TypeScript (#69424)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1505

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:29:11 +13:00
Nathan Voxland
c2172311f5 Better queue testing with memory queue 2026-02-17 16:19:34 -06:00
Oleksandr Yakushev
d4702e10e0 Merge remaining match -> match-many rewrites (#69686)
* [match] Implement match-many as a replacement for match

* [match] Add proper docs to match-lite and match-many
2026-02-17 23:56:04 +02:00
Nathan Voxland
5a7bcfab93 Better naming for storing messages in the appdb queue 2026-02-17 15:37:43 -06:00
Braden Shepherdson
c8cd828410 [MBQL lib] Don't export a dynamic var; add with-card-clean-hook macro (#69662)
Fixes QUE2-354.

`lib/with-card-clean-hook` can be used to bind a callback function to
any material changes made by the `lib.convert/clean` process, which
generally indicates errors.
2026-02-17 21:36:48 +00:00
Edward Paget
aa5c870dc4 fix: cancelling remote sync tasks dismisses modal (#67613)
* fix: cancelling remote sync tasks dismisses modal

Previously we didn't close this modal until the task reached a
'cancelled' state which could take several seconds.

* fixup! PR feedback
2026-02-17 15:08:18 -06:00
Nathan Voxland
decbc82b1a Code review fixes 2026-02-17 14:56:27 -06:00
Kevin Kelleher
f4aa0cc722 Visualizer trend lines and bug fixes: colors, settings, legends, axes (#69296) 2026-02-17 15:54:47 -05:00
Nathan Voxland
bd0f5b3b69 Merge remote-tracking branch 'origin/master' into persistent-queue 2026-02-17 14:33:54 -06:00
metamben
764befaffb Document :metabase.lib.field/simple-display-name (#69590)
* Document :metabase.lib.field/simple-display-name

Closes QUE2-286

* Fix merge
2026-02-17 23:08:32 +03:00
metamben
dbced47022 Name the default join strategy (#69748)
Closes QUE2-285

The original idea was making the :strategy key required and leaving the setting of the value to the normalization, but
I decided not to go down that road. Here's why: there are multiple places on the path of constructing a join where we
can specify the join strategy but don't have to. These steps are not going through normalization and introducing
normalization would be inefficient and feel strange. Also, it would need to be done at several points, so it doesn't
seem a gain in the end. Because of this, all this PR does is naming the default strategy, so that changing it should
be possible at a single point. (Doing this would be a bad idea, so this PR is meant to be a documentation
improvement.)
2026-02-17 23:08:21 +03:00
Edward Paget
224d17965d fix: allow uploads when schema is unrestricted (#69657)
* fix: allow uploads when schema is unrestricted

* fixup! add upload enabled flag

* Update impl.clj

* fixup! where upload flag is set
2026-02-17 13:26:36 -06:00
Abed Habli
0b644a038f Docs v59: Nav UI update -- Grid icon and Admin rename (#69803)
* Update gear icon

* Update docs/data-modeling/json-unfolding.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-modeling/json-unfolding.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/sdk/quickstart-with-sample-app.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/sdk/quickstart.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/full-app-embedding-quick-start-guide.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/full-app-embedding-quick-start-guide.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/user-provisioning.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/permissions/application.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/permissions/data.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/util/resources/introduction.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/usage-and-performance-tools/audit.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Apply suggestion from @jeff-bruemmer

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/public-links.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/public-links.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/api-keys.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/api-keys.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/api-keys.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Remove few "ons"

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-17 20:16:14 +01:00
github-automation-metabase
65c102daf2 Auto-update documentation for master (#69781)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-17 11:14:20 -05:00
Nathan Voxland
5da65b6c52 Un-publishing remote-sync'ed library tables should remove them from the git repo (#69757) 2026-02-17 09:57:31 -06:00
Jeff Bruemmer
5f66a26a53 docs - one-shot sql gen (#69766) 2026-02-17 15:36:16 +00:00
Jakub Chodorowicz
75db6b5973 split large data model shared spec cypress file (#69744)
* split large data model shared spec cypress file

* split 2nd group further, rename files
2026-02-17 16:31:27 +01:00
Uladzimir Havenchyk
085fc52dca chore: cleanup relationships which we never show (#69786) 2026-02-17 17:24:11 +03:00
Uladzimir Havenchyk
b404c13d0c chore: convert dashboard actions to typescript (#69737)
* chore: convert dashboard actions to typescript

* cleanup

* fix unit test

* address review

* fix typecheck
2026-02-17 17:14:08 +03:00
Uladzimir Havenchyk
727664ccc6 chore: cleanup moment leftovers (#69733) 2026-02-17 16:29:31 +03:00
Jeff Bruemmer
97fa5da0c0 docs - embedding native question (#69762)
native question
2026-02-17 08:28:01 -05:00
Kamil Mielnik
a1b8cbca83 GDGT-1781 Fix flaky "should check out transform into a new workspace from the transform page" e2e test (#69619) 2026-02-17 13:26:48 +00:00
Gabriel Moreno
e0d953e257 Implement improved illustration for in-app Library upsell (#69760)
feat: add new library upsell illustrations
2026-02-17 09:14:08 -04:00
Nemanja Glumac
f405f3d36a Remove set-value and unset-value from "resolutions" (#69787) 2026-02-17 13:10:40 +00:00
Fraser
554bb10750 Convert Heading to TypeScript (#69064)
* Convert Heading to TypeScript

Closes DEV-1409

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Delete heading and replace with title

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-18 00:20:06 +13:00
Kamil Mielnik
c51eeace1d Visualization Typescript Conversions - lib/dom.js (#69630) 2026-02-17 17:30:01 +07:00
Mahatthana (Kelvin) Nomsawadi
da01813210 Fix flaky view-and-curate-content.cy.spec.ts (#69749)
Fix flaky test
2026-02-17 10:03:49 +00:00
Fraser
2a12752ec7 Convert lib/security to TypeScript (#69422)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1504

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:45:14 +13:00
lbrdnk
7da41b4874 Add uv to build docs and dev-install (#69727)
* Add uv to build docs and dev-install

* Update docs/developers-guide/build.md

Co-authored-by: bryan <bryan.maass@gmail.com>

* Add also python to mise.toml

---------

Co-authored-by: bryan <bryan.maass@gmail.com>
2026-02-17 09:19:35 +01:00
Kamil Mielnik
7cab7b1458 GDGT-1740 Datamodel Typescript Conversions (#69343) 2026-02-17 15:12:39 +07:00
Fraser
801720f077 Convert lib/schema_metadata to TypeScript (#69425)
* Convert `lib/schema_metadata` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1506

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 14:03:57 +13:00
Cam Saul
bd1e91191c Map Snowflake big integers to :type/BigInteger (#67609)
* Map Snowflake big integers to :type/BigInteger (fix #63600)

* Test fixes 🔧

* Test fixes 🔧

* Test fix 🔧

* More test fixes 🔧

* Another round of test fixes 🔧

* (Hopefully) final test fix 🔧

* Code cleanup

* Revert changes that broke Clickhouse test

* Test fix 🔧
2026-02-16 17:03:13 -08:00
Fraser
d4cb2fb735 Convert Alert to TypeScript (DEV-1493) (#69415)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 13:47:08 +13:00
Rodrigo López Dato
5259af771e Fix navigate_to not doing anything in full-app embedding (#69761) 2026-02-16 23:47:11 +00:00
Romeo Van Snick
f3f72f8cb3 Fix missing availableHeight on model native editor (#69723)
* Fix missing availableHeight on model native editor

* Add repro for metabase#69722
2026-02-17 10:42:47 +11:00
Fraser
a46e4da604 Convert PermissionsTabs to TypeScript (#69080)
* Convert PermissionsTabs to TypeScript

Closes DEV-1425

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 12:21:15 +13:00
Fraser
4568848fb0 Convert common/hooks/use-scroll-on-mount to TypeScript (#69440)
* Convert `common/hooks/use-scroll-on-mount` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1518

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:20:51 +13:00
Fraser
a6bf8e9326 Convert lib/encoding to TypeScript (#69413)
* Convert `lib/encoding` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1490

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:19:35 +13:00
Kevin Kelleher
32b8ab866d Default viz behavior fixes (#69664) 2026-02-16 17:39:16 -05:00
Egor Grushin
bbf5aebd5a Gdgt 1774 incremental update field not displaying in transforms (#69740)
* GDGT-1774 fetch metadata to enable field picking in incremental transform settings

* GDGT-1774 add e2e reproduction
2026-02-16 22:01:44 +00:00
Ryan Laurie
55d4145794 Update workflow triggers (#69758)
update workflow triggers
2026-02-16 19:47:56 +00:00
Anderson
98f4633388 Add tracking events for when Dependency Graph is opened for an entity (#69604)
* Add events for transform run tags and dependency diagnostics row selection

* Fix e2e test

* Adjust event as per review / Fix e2e tests

* Add tracking events for when Dependency Graph is opened for an entity

* Add remaining e2e tests

* Update simple_event/jsonschema/1-0-0
2026-02-16 18:59:36 +00:00
Dan Stone
d987764034 Fix bigquery/snowflake transforms tests (#69566)
* Add python transforms .yml for manually verifying flakes

* Fix bigquery/snowflake failing tests

* Fix bigquery name quoting

* Use explicit schema in table gens

* Schema fixes for bigquery
2026-02-16 18:34:24 +00:00
Maksym Yakubych
7bf8c80d42 fix: double new lines are not pasted correctly into metabot prompt input (#69493) 2026-02-16 09:42:37 -06:00
Maksym Yakubych
a971f7972b feat: add @ mention to metabot placeholders (#69374) 2026-02-16 09:41:32 -06:00
Nicola Mometto
cfcba5160e remove task logs from usage analytics (#69739) 2026-02-16 14:30:56 +00:00
metamben
04e14dcee2 Remove :metabase.lib.field/original-temporal-unit and document friends (#69627)
* Remove :metabase.lib.field/original-temporal-unit and document friends

Closes QUE2-287

* Remove unused alias
2026-02-16 16:34:00 +03:00
Jeff Bruemmer
832a04aa91 docs - box plot (#69689)
* box plot docs

* Optimized 3 images, saved 221.8 KB (44.8% smaller)

* Apply suggestion from @jeff-bruemmer

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-02-16 13:24:40 +00:00
Abed Habli
c5591f5ece Docs: Add screenshots to Data Studio docs (#69634)
* Add screenshots to Data Studio docs

* Optimized 8 images, saved 757.5 KB (38.2% smaller)

* Update docs/data-studio/data-structure.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Delete docs/data-studio/images/sync-settings.png

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-16 12:07:28 +00:00
metabase-bot[bot]
bf1610f1cd [chore] Update E2E test timings with recent data (#69685)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-16 10:05:05 +00:00
Romeo Van Snick
e1813fedb5 Fix more measure unit tests (#69596)
* Rewrite test to use Lib.createTestQuery

* Force OpaqueDatasetQuery to be used

* Break cyclic imports
2026-02-16 19:51:39 +11:00
Kamil Mielnik
3339413f6e GDGT-1775 Convert Gauge Viz to Functional Component + Typescript (#69468) 2026-02-16 15:19:36 +07:00
Kamil Mielnik
2958401e6e GDGT-1772 Convert Progress Visualization to Typescript + Functional Component (#69449)
* Refactor Progress viz to TypeScript and a function component

* Always run the effect
2026-02-16 15:19:01 +07:00
Nemanja Glumac
63bae84a2d Restore 60 minute timeout for BigQuery and Snowflake (#69687) 2026-02-15 14:39:14 +01:00
Ryan Laurie
ea30b8973d Fix Circular Dependency in useGetPlan (#69672)
fix circular dependency
2026-02-14 19:53:23 +00:00
Oleksandr Yakushev
7beb2e3eb1 [match] Implement match-many as a replacement for match (#68659)
[match-lite] Add support for &match anaphor and better nil handling
2026-02-14 16:24:48 +02:00
Nemanja Glumac
1f5eef83b0 Reduce the CI test timeout to 40 minutes (#69625) 2026-02-14 05:37:44 -07:00
Anderson
8a39fdc126 Add tracking events for transform run tags update and dependency diagnostics row selection (#69531)
* Add events for transform run tags and dependency diagnostics row selection

* Fix e2e test

* Adjust event as per review / Fix e2e tests
2026-02-13 20:38:45 -03:00
Denis Berezin
c2aaa12429 Python library upsell (#69600)
* Temp

* Separate EE and OSS transforms upsell logic

* Remove upsell
2026-02-13 19:52:57 -03:00
Anderson
d38d54ec94 Prevent editing snippets from question editor when remote sync is read-only (#69147)
* Prevent snippets to be edited from question editor when remote sync is read-only

* Fix test
2026-02-13 19:28:27 -03:00
Aleksandr Lesnenko
e525135245 rework chart selection ui (#69289) 2026-02-13 17:27:45 -05:00
Kevin Kelleher
d6da6f1198 Fixes for email clients in dark mode (#69023) 2026-02-13 17:08:15 -05:00
Braden Shepherdson
4d9dc19271 [deps] Ignore "soft" refs (in :fields clauses) in deps analysis (#69198)
Fixes QUE-3044.

The QP will ignore refs in `:fields` clauses which cannot be resolved, since they're output only and not critical to the meaning of the query. This change makes the deps analysis treat these "soft" refs the same way - they are not considered to break the queries.

I added some commented tests that are now captured as part of QUE-3081 rather than part of this PR.
2026-02-13 21:23:18 +00:00
Anderson
93e5f86792 Fix docs link on incremental transforms section (#69648) 2026-02-13 21:19:48 +00:00
Denis Berezin
b57eb0d2c7 Dashboard category filter not correctly populated when using multiple datasources in one graph (#69318)
* Add repro e2e test

* Dashboard filter values when connected to card with multiple datasets

* Fix kondo
2026-02-13 23:51:23 +03:00
Ryan Laurie
c55a5d23a1 Dont show hosting upsell to pro self hosted users (#69522)
dont show hosting upsell to pro self hosted users
2026-02-13 13:19:15 -07:00
Braden Shepherdson
ce9a7027cf [MBQL lib] "Befriend" legacy-mbql module, drop some exported namespaces (#69578)
Fixes QUE2-349.

This removes several namespaces from the export list for `lib` which were only used by `legacy-mbql`.

- `metabase.lib.filter.desugar.jvm`
- `metabase.lib.hierarchy`
- `metabase.lib.schema.binning`
- `metabase.lib.schema.constraints`
- `metabase.lib.schema.middleware-options`
- `metabase.lib.schema.settings`
- `metabase.lib.schema.window`
2026-02-13 20:01:20 +00:00
Nemanja Glumac
ff9690156a Remove forced jsdom resolution (#69575) 2026-02-13 20:18:46 +01:00
github-automation-metabase
34fc6597f3 Auto-update documentation for master (#69606)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-13 14:17:42 -05:00
Jeff Bruemmer
6cc10beb56 docs - agent API (#69647) 2026-02-13 18:59:39 +00:00
Dan Stone
fe3b6f83d7 Ensure race free waiting for overlapping transforms (#69287)
* Ensure race free waiting for overlapping transforms

Previously transforms could contend for the is_active slot.
A common outcome (observed with two overlapping schedules) was that one transform would crash (due to the duplicate key violation).

This commit ensures a collision will fallback to waiting to try again rather than crashing (and alerting the user).
2026-02-13 17:35:22 +00:00
Nathan Voxland
45a8927bb8 Revert "Do a rollback before discard all (#69026)" (#69633)
This reverts commit 42d0d35dbd.
2026-02-13 11:01:38 -06:00
Sébastien
60b86d85a5 Fixes isSticky class not being properly applied to dashboard parameters (#69623) 2026-02-13 17:57:16 +01:00
Nemanja Glumac
9c8bf32532 Remove Claude review workflows (#69632)
[ci skip]
2026-02-13 17:56:03 +01:00
Nathan Voxland
fe325b3de7 Improve remote sync errors with missing objects (#69591) 2026-02-13 10:22:09 -06:00
bryan
07fbc6997e Use sqlglot for SQL parsing via GraalVM Polyglot (#68911)
Introduces a unified `sql-tools` API for SQL parsing with swappable backends:
- Macaw (Java, existing) — moved from `metabase.driver.sql`, behavior preserved
- SQLGlot (Python, new) — broader dialect support via GraalVM Polyglot

Architecture: callers go through `sql-tools` which dispatches to either backend
via the `MB_SQL_TOOLS_PARSER_BACKEND` setting (default: sqlglot). The old
Macaw calls (parsed-query -> ast -> field-references) are replaced
with a `sql-tools` API (e.g. `sql-tools/referenced-fields`,
`sql-tools/validate-query`).

SQLGlot runs Python inside GraalVM Polyglot contexts managed by a reusable pool
to amortize initialization cost. The Python source and SQLGlot library are
bundled into the uberjar via a dedicated build step.
2026-02-13 15:57:17 +01:00
Jeff Bruemmer
28585e4119 docs - remove auth (#69594)
remove auth
2026-02-13 15:37:07 +01:00
John Swanson
b6b77a19e7 record group membership removals in activity log (#69316)
* record group membership removals in activity log

Previously the `PUT /api/membership/:group-id/clear` and
`DELETE /api/membership/:id` endpoints did not emit group membership
deletion events.

In the long run it would be better if `t2` were the interface for
PermissionsGroupMembership, so users didn't need to call these "blessed"
functions. But for now, let's go along with the existing pattern here,
have some blessed functions for doing things, and throw exceptions if
someone does a direct `t2/delete!` on a `:model/PermissionsGroupMembership`.

* use macro for more obvious workaround
2026-02-13 05:10:11 -08:00
Timofey Kachalov
890771e40e Prepare Shoppy Sample App GH job to run synthetic monitoring tests (#69492) 2026-02-13 16:59:32 +04:00
Kamil Mielnik
3c724995fb GDGT-1760 Remove Code & BoldCode components (#69348) 2026-02-13 12:29:57 +00:00
Kamil Mielnik
3bd26a0179 GDGT-1761 Remove Grid component (#69351) 2026-02-13 18:42:14 +07:00
Nemanja Glumac
55959131e9 Remove unused Tusk GitHub workflow (#69612) 2026-02-13 11:46:16 +01:00
Nemanja Glumac
9845f0e964 Fix ci-test-config driver quarantine name translation (#69615)
The ci-test-config.json uses driver directory names (e.g., "bigquery-cloud-sdk")
but the mage code uses internal driver keywords (e.g., :bigquery). This mismatch
meant quarantined drivers like bigquery were not being recognized.

Now uses the existing driver-directory->drivers mapping to translate config names
to internal keywords, with fallback to direct keyword conversion for names that
match (like "databricks").

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 11:28:19 +01:00
Mahatthana (Kelvin) Nomsawadi
7efad1c105 Correct the modular embedding preview usage count (#69473)
* Correct the modular embedding preview count as :internal

* Add tests

* Fix the modular embedding preview count while not breaking alerts emails

* Fix E2E tests

* Fix wrong e2e syntax
2026-02-13 09:39:32 +00:00
Romeo Van Snick
82d5e7b7ed Native query test helper (#69402)
* Add schema for test-native-query-spec

* Implement test-native-query helper

* Add js wrapper for test-native-query

* Add ts wrapper for test-native-query

* Make common parts optional

* Fix types

* Fix temporal-unit test spec

* Handle snippet tags

* Fix temporal-unit tags

* Fix card tag spec

* Simplify schema

* Add unit tests for createNativeQuery

* Add tests for test-native-query

* Add missing options

* Fix types

* Actually resolve field ref

* Code style

* Add native-query api endpoint

* Add h.createTestNativeQuery helper

* Add test for required, widget-type and default options

* Move parsing into test-spec module as it is part of the implementation

* Add example e2e test use of H.createTestNativeQuery

* Use coercer instead of decoder to validate spec too

* Fix lint

* Move adjust to update-vals

Co-authored-by: Braden Shepherdson <braden@metabase.com>

* Match threading style

* Add test for optional template tagsfg

---------

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2026-02-13 02:53:16 +00:00
Fraser
b69c4d4e26 Convert PermissionsEditorBreadcrumbs to TypeScript (#69052)
* Convert PermissionsEditorBreadcrumbs to TypeScript

Resolves DEV-1397

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 22:21:41 -03:00
Fraser
92157c0c06 Convert PermissionsSelectOption to TypeScript (#69054)
* Convert PermissionsSelectOption to TypeScript

Closes DEV-1399

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 22:20:33 -03:00
Anderson
3e5a4dc818 When instance is not on trial, still allow them to start Transforms trial if available (#69499)
* show both transforms tiers even when on trial

* Show upgrade modal in place when clicking Upgrade to Pro

* Improve comments

* Show upsell transforms trial variant when available for instance not on trial

* Fix ts

* Say 'Start trial' when trial is available
2026-02-12 22:18:13 -03:00
metamben
72699a1927 Remove :lib/model-display-name (#69579)
Closes QUE2-296
2026-02-13 02:50:46 +03:00
Romeo Van Snick
9f22d94341 Move test helper parser to lib (#69405)
* Use correct type for order-bys

* Move parser for test-query-spec into implementation

* Be more strict in test

* Convert another e2e test to prove the parsing works

* Make args optional in test-query-spec

* Use threading instead of partial

Co-authored-by: Braden Shepherdson <braden@metabase.com>

---------

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2026-02-12 23:18:40 +00:00
Nick Fitzpatrick
b7b9d20ad7 Move app switcher into Dependency Graph (#69128)
* move app switcher into Dependency Graph

* adjusting unit test

* remove z-index nonsense

* moving the app switcher up to DependencyGraphPage, small change to SelectItem
2026-02-12 17:53:55 -04:00
Noah Moss
aa4389bd60 Correct function for fetching field values in Metabot tools (#69589)
* switch function for metabot fetching field values

* refactor tests

* fix lint

* fix tests - keep existing behavior of auto-creating field values if needed
2026-02-12 16:50:14 -05:00
Noah Moss
e70631b3ab Move agent api reference out of docs/ (#69567)
move agent api reference
2026-02-12 16:36:32 -05:00
Anderson
52c4ff856d Fix 'Upgrade to Pro' button to open upgrade modal / Show two transforms tier options when on trial (#69387)
* show both transforms tiers even when on trial

* Show upgrade modal in place when clicking Upgrade to Pro

* Improve comments
2026-02-12 16:56:53 -03:00
Nathan Voxland
7bf638e16e Audit DB should exclude databasechangeloglock (#69487)
auditdb should exclude databasechangeloglock as well
2026-02-12 13:23:37 -06:00
metamben
c950231ec9 Document source-field-join-alias and resolve TODOs (#69503)
Fixes QUE2-297
2026-02-12 22:05:42 +03:00
metamben
3c774eccc8 Add missing multimethods for datetime-subtract (#69324)
Closes QUE2-336
2026-02-12 22:05:27 +03:00
Maksym Yakubych
81d20a97b9 fix: mention popup doesn't close when clicking esc (#69485) 2026-02-12 11:46:13 -06:00
Cam Saul
7c05a09619 Ban legacy keys in column metadata (#69504)
* [Lib] remove deprecated/confusing `:source-alias` key from col metadata

* Metadata schema cleanup

* Test fixes 🔧

* New test fix 🔧

* Ban legacy keys in column metadata

* Fix most tests

* More test fixes 🔧

* Kondo

* Test fix 🔧
2026-02-12 09:26:21 -08:00
Sébastien
0a05ffd76a Implement auto-generated props tables for modular embedding (#69407)
* Add TypeDoc-friendly interfaces for EAJS web component documentation

* Add TypeDoc config for EAJS web component docs generation

* Generate EAJS web component props tables via TypeDoc

* Replace manual parameter lists with auto-generated props tables

* Fixed file references in components.md and enforced types in embed.ts

* .

* .

* .

* added detail on a prop and uncommited *.md files

* added info about attributes needing to be stringified

* .
2026-02-12 16:53:03 +01:00
github-automation-metabase
e1346eb492 Update translations 2026-02-10 (#69372)
* Update translation sources 2026-02-10

* Update translations

* update localization e2e test

* Wochentag

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2026-02-12 14:45:50 +00:00
Nemanja Glumac
1f03ce8fca Update Jest snapshot headers for Jest v30 compatibility (#69564)
Jest v30 validates that snapshot files have the current documentation URL.
Updated the header from the old shortened URL to the new official URL.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 14:43:09 +00:00
Nick Fitzpatrick
bb9c1a1171 add 59 to version-helpers.ts (#69500) 2026-02-12 09:24:06 -04:00
Kamil Mielnik
2291e7f38b GDGT-1776 Query Builder transform fails at join stage (#69552)
* Fix virtualized list items rendering

* Add a repro for GDGT-1776

* Fix GDGT-1776

* Remove isHidden prop from MiniPickerItem and instead just do not render items that should be hidden

* Clean up

* Fix var access
2026-02-12 20:14:54 +07:00
Mahatthana (Kelvin) Nomsawadi
d0d678d9d8 Add "New embed" to command palette in OSS (#69447)
* Improve type ergonomics

* Add tests

* Fix proper discrinimated unions

* Add new keywords to match modern terms

* Fix types

* Sort basic actions in command palette

* Fix tests
2026-02-12 13:10:15 +00:00
Nicola Mometto
09ff1de363 Remove LIMIT in query builder transforms (#69347)
* feat(python-transforms): massage query

* feat(transforms-util): disable-max-results

* feat(QP): respect disable-max-results

* feat(transforms/ui): set disable-max-results

* add tests

* export function in lib

* use disableMaxResults

* more tests

* add e2e test

* 0 max rows is no limit

* fix test

* comment

* address review comments

* Remove trailing newline
2026-02-12 12:42:09 +00:00
Nemanja Glumac
adb448828b Upgrade Jest to v30 (#69490) 2026-02-12 12:19:28 +01:00
Nemanja Glumac
a9c4781d78 Include the relevant step outcome in Trunk inputs (#68947) 2026-02-12 12:04:28 +01:00
Nemanja Glumac
2391e04ea3 Fix the release-log workflow (#69547)
Use prepare-release-scripts action in release-log workflow

Simplify the workflow by using the shared action instead of
manually setting up bun and building release scripts.

This works because the workflow always checks out master,
so the action from master (which uses bun) is always used.

Fixes: DEV-1544

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 11:40:32 +01:00
Ngoc Khuat
636dc63968 Require explicit user approval for agent data access (#69280) 2026-02-12 10:15:56 +00:00
Nemanja Glumac
867aa1ae83 Conditionally resolve the package manager in pre-release (#69545) 2026-02-12 10:01:31 +01:00
lbrdnk
985082f059 Make ci-report work without GNU timeout (#69453)
* Make ci-report work without GNU timeout

* Destroy process on timeout

* Cherry-pick b9ff360230

---------

Co-authored-by: Bryan Maass <bryan.maass@gmail.com>
2026-02-12 09:22:31 +01:00
Sébastien
6b5577a351 Fix flaky embedding sdk backward compatibility test (#69540)
* fixed e2e test

* .
2026-02-12 07:26:24 +00:00
Romeo Van Snick
8d285e7bee Fix broken measure unit tests (#69515)
* Allow passing measures to entities schema

* Fix measures test

* Use toJsQuery
2026-02-12 13:57:47 +11:00
Fraser
fe11f27110 Convert JobInfoApp to TypeScript (#69073)
* Convert JobInfoApp to TypeScript

Closes DEV-1418

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:25:11 +13:00
Fraser
3bceaecf2b Convert PasswordReveal to TypeScript (#69061)
* Convert PasswordReveal to TypeScript

Closes DEV-1406

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:24:45 +13:00
Fraser
85b82b52f6 Convert CopyWidget to TypeScript (#69056)
* Convert CopyWidget to TypeScript

Closes DEV-1401

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:23:32 +13:00
Fraser
8e03727b66 Convert dashboard/actions/revisions to TypeScript (#69437)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1515

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 15:23:04 +13:00
Fraser
b5e052b0c9 Convert JobTriggersModal to TypeScript (#69072)
* Convert JobTriggersModal to TypeScript

Closes DEV-1417

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:40:52 -07:00
Fraser
bdb2ce7dae Convert UsefulQuestions to TypeScript (#69069)
* Convert UsefulQuestions to TypeScript

Closes DEV-1414
2026-02-11 17:39:55 -07:00
William
17a3afa85e Add table template tags (#68922)
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-02-11 23:28:16 +00:00
Fraser
50801fc441 Pin bun version in workflows (#69514) 2026-02-12 12:04:10 +13:00
Denis Berezin
31516230f5 Update Upsell to match design (#69488)
* Update Upsell to match design

* Remove loader for trial message
2026-02-12 02:03:02 +03:00
Fraser
a678c2ff8e Convert caching/utils to TypeScript (#69444)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1522

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 11:31:19 +13:00
Fraser
c4090623a9 Convert moderation/selectors to TypeScript (#69445)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1523

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 11:26:31 +13:00
Cam Saul
570952497a [Lib] remove deprecated/confusing :source-alias key from col metadata (#69314)
* [Lib] remove deprecated/confusing `:source-alias` key from col metadata

* Metadata schema cleanup

* Test fixes 🔧

* New test fix 🔧
2026-02-11 13:56:41 -08:00
da
ef622a4832 Add entity id and entity type to the dependency calculation error (#69001)
* Initial commit

* Fix tests

* Fix events test
2026-02-11 18:53:49 -03:00
Fraser
43daa3b222 Convert AccountLayout to TypeScript (#69067)
* Convert AccountLayout to TypeScript

Closes DEV-1412

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 10:48:03 +13:00
Aleksandr Lesnenko
f0582cb46a Add boxplot visualization (#68104)
* add boxplot visualization type

* Add boxplot viz type visual tests (#68327)

boxplot visual tests
2026-02-11 16:39:14 -05:00
Nemanja Glumac
360ae8c713 fix: Snyk workflow using wrong working directory for release/yarn.lock (#69510)
The previous fix ran `cd release && bun install --yarn` which changed the
working directory for subsequent commands. The sed command then tried to
access `release/yarn.lock` from within the `release/` directory, resulting
in "sed: can't read release/yarn.lock: No such file or directory".

Split into separate steps with explicit working-directory for clarity.
The sed commands now continue on error to let Snyk report parsing issues
directly rather than failing on the workaround.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 22:27:33 +01:00
John Swanson
34837bc9bb Implement DB-level caching of premium features (#69241)
Premium feature token checks are cached per-instance in memory with a 12h TTL. During rolling deploys after a plan upgrade, different instances can disagree about which features are available:

   1. Request hits instance A (old cache) → reports old features
   2. Request hits instance B (freshly started, no cache) → reports new features
   3. Frontend says "upgrade successful!"
   4. Request hits instance A again → old features are back

This flapping means the frontend can't reliably detect when an upgrade has landed.

## Solution

### DB-hash-aware cross-instance cache

Replace the per-instance in-memory TTL cache with a two-layer caching scheme coordinated through the DB:

 - A **local in-memory cache** holds the full token status (features, validity, etc.)
 - A **DB table** (`premium_features_token_cache`) stores only a SHA-256 hash of the token status, keyed by a hash of the token itself. The DB never stores actual features — just enough to coordinate freshness across instances.

When a token check comes in:
- If the local cache matches the DB hash and is < 12h old: serve it immediately
- If it matches the DB hash and is < 36h old: serve the stale data and refresh asynchronously in the background
- If the DB hash doesn't match (another instance refreshed), or the cache is > 36h old, or this is a cold start: synchronous MetaStore fetch

This ensures all instances converge quickly after a plan change while keeping MetaStore traffic low. Cold-starting instances always hit the MetaStore — there's no way to bootstrap features from the DB alone, since it only stores hashes.

### Checker stack (inner to outer)

1. **`store-and-airgap-token-checker`** — hits MetaStore or validates airgap token
2. **`circuit-breaker-token-checker`** — circuit breaking + timeout
3. **`db-hash-aware-token-checker`** — the core caching layer (described above)
4. **`local-cached-token-checker`** — 5s TTL memoization to avoid hitting the DB on every request
5. **`error-catching-token-checker`** — wraps exceptions into `{:valid false}` responses

The 5s local cache means we hit the DB at most once every 5s, even during the grace period.

### Force-refresh endpoint

`POST /api/premium-features/token/refresh` clears all caches and synchronously re-checks against the MetaStore. The frontend uses this when polling for new features after a purchase (`useTokenRefreshUntil` in `UpgradeModalLoading`, `MetabotSettingUpModal`, `TransformsSettingUpModal`). A cookie-based mechanism propagates the invalidation to other instances so they clear their local caches on the next request.
2026-02-11 13:11:52 -08:00
Nemanja Glumac
dccfcc9db1 fix: Snyk scan failing after bun migration (#69498)
Root Cause:
Bun's `bun install --yarn` command has a bug where it normalizes version
ranges inconsistently in the generated yarn.lock:

- Alias entries normalize ranges: "safer-buffer@>= 2.1.2 < 3"
  (converts "< 3.0.0" to "< 3")
- Dependency specs keep original: safer-buffer ">= 2.1.2 < 3.0.0"
  (preserves the ".0.0")

Snyk performs exact string matching when resolving dependencies to their
lock file entries. When it sees `safer-buffer@>= 2.1.2 < 3.0.0` as a
dependency, it looks for that exact string in the alias list, but only
finds `safer-buffer@>= 2.1.2 < 3`, causing the error:

  "Dependency safer-buffer@>= 2.1.2 < 3.0.0 was not found in yarn.lock"

Solution:
Add a post-processing sed command that normalizes version ranges in the
dependency specifications to match the aliases. This transforms:
- "< 3.0.0" → "< 3"
- "< 3.0" → "< 3"

This ensures Snyk can match dependencies to their resolutions.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:53:34 -03:00
Edward Paget
6d1b58aaa2 feat: add a stable sort for card parameters serdes (#69478)
Sorts parameters by their uuid to ensure that we maintain an order for
parameters across exports no matter the order they are serialized to the
database in.
2026-02-11 14:39:12 -06:00
John Swanson
4dcab243b9 Don't attempt to add revisions for viewing docs (#69305)
Luckily a bug saved us from *actually* creating revisions here (the
`before-update` hook doesn't get an actual instance in this case). But
... we shouldn't be attempting it.
2026-02-11 11:45:45 -08:00
Nick Fitzpatrick
4501e69eb0 add build cljs to pre-release steps (#69495)
add buuild cljs to pre-release steps
2026-02-11 14:53:41 -04:00
Nemanja Glumac
b9363e3f75 Set up bun authenticated (#69491)
This prevents API rate limits.
2026-02-11 19:29:36 +01:00
Nemanja Glumac
1ad08d2ac9 Add automatic build tools installation to dev-install (#69451)
Offer to install essential build tools during setup, which are required
for compiling native extensions in development dependencies.

macOS:
- Detects Xcode Command Line Tools via xcode-select -p
- Triggers native installer dialog and polls for completion
- 10-minute timeout with manual installation fallback

Linux (multi-distro support):
- Debian/Ubuntu/Mint/Pop: build-essential
- Fedora/RHEL/CentOS/Rocky/Alma: Development Tools group
- Arch/Manjaro/EndeavourOS: base-devel
- openSUSE/SLES: devel_basis pattern
- Unknown distros: manual installation guidance

The check runs as part of step 1 (prerequisites) and is idempotent -
existing installations are detected and skipped with a success message.

* Add progress indicator during Xcode CLT installation wait

Show dots every 10 seconds while polling for installation completion,
so users know the script is still running during the wait.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 18:32:26 +01:00
Maksym Yakubych
1be2cb8497 fix: error message for unauthenticated requests is generic (#69352) 2026-02-11 16:54:01 +00:00
Nicolò Pretto
b9e6c5bc06 feat(sdk): add isHostAppInDevMode (#69450)
* feat(sdk): add isHostAppInDevMode

* i forgot package.json
2026-02-11 16:55:35 +01:00
Fraser
b806fb5b31 Convert AdminAwareEmptyState to TypeScript (#69055)
* Convert AdminAwareEmptyState to TypeScript

Closes DEV-1400

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:53:13 +02:00
Nemanja Glumac
f94f6a847a Remove @peculiar/webcrypto polyfill from ClojureScript tests (#69475)
This completes the removal of `@peculiar/webcrypto` from the codebase,
following the Jest setup cleanup in #69466.

Changes:
- Update `polyfills.cljc` to use Node's native `crypto.webcrypto`
- Remove `@peculiar/webcrypto` from package.json

The previous comment about needing Node v23+ was outdated:
- `crypto.webcrypto` available since Node 15
- `globalThis.crypto` available since Node 19
- Node 22 (current LTS) fully supports it

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 15:44:03 +00:00
Nick Fitzpatrick
f37171d483 Add loading state to pull changes (#69380)
adding unit test
2026-02-11 11:26:32 -04:00
Maksym Yakubych
77cb535614 fix: drag handler selecting text in query editor (#68970) 2026-02-11 11:12:19 -04:00
Nemanja Glumac
3532b35b00 Remove @peculiar/webcrypto polyfill from the Jest setup (#69466)
* Use native NodeJS cryppolyfill in fe unit tests

* Force jose library to use Node.js runtime in Jest tests

The jose library's browser runtime expects CryptoKey to be globally
available, which jsdom doesn't provide. This caused tests using JWT
signing (via jose) to fail with "CryptoKey is not defined" after
switching from @peculiar/webcrypto to Node's native webcrypto.

By mapping jose to its Node.js runtime via moduleNameMapper, we avoid
the CryptoKey dependency since the Node runtime uses require('crypto')
directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 15:48:45 +01:00
Maksym Yakubych
d77ae0cedb feat: tooltips for metabot message action buttons (#69369) 2026-02-11 14:43:10 +00:00
metamben
8239cbfa00 Prevent expression editor from forcing literal types (#67647)
* Prevent expression editor from forcing literal types

Closes #63910
2026-02-11 14:37:45 +00:00
Nemanja Glumac
dd2b2929a1 Update FE Claude.md scripts instructions (#69463) 2026-02-11 15:25:05 +01:00
Riley Thompson
9cd60a5d77 Set bigquery transport options with read timeout (#69306)
* set read timeout

* add tests
2026-02-11 08:53:21 -05:00
Nemanja Glumac
d0cef57a4f Remove superfluous jest-localstorage-mock (#69455) 2026-02-11 14:34:35 +01:00
Nemanja Glumac
f2bb215346 Fix determine-driver-skips failing on a release branch (#69448) 2026-02-11 09:26:48 -04:00
Maksym Yakubych
7a1aec685f fix: line height of placeholder text in metabot side panel should be 20px (#69377) 2026-02-11 10:05:12 -03:00
Kamil Mielnik
5474fca0c0 GDGT-1531 - Opening a transform should open tab immediately (#69224) 2026-02-11 18:11:11 +07:00
Nemanja Glumac
ab7baf7ca7 Upgrade webpack (#69341) 2026-02-11 10:12:59 +01:00
Mahatthana (Kelvin) Nomsawadi
d7607ccf8a support targetCollection in CreateDashboardModal (#69359)
* Remove old and unused props

* Support `targetCollection` in the CreateDashboardModal

* Add tests

* Handle special collection name e.g. `root`, `personal`

* Address review

* Update test names
2026-02-11 09:00:41 +00:00
Sébastien
d6082bba08 Fixes show detail button showing in embeds (#69338)
fixes show detail button showing in embeds
2026-02-11 06:33:32 +01:00
Anderson
1d0eaf9ca8 Show confirmation popup when overwriting data during remote sync setup (#68525)
* Report conflicts on transforms/snippets/lib

[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)

Co-authored-by: edpaget<ed@metabase.com>

* fixup! store conflicts in remote-sync-task table

* fixup! make conflict checking spec driven

* Restore initial implementation (implement conflict modal when pulling for the first time)

* Fix modal not opening when in data studio

* Don't set version in task when it fails with conflict / Adjust conflict options / Start e2e tests

* Add e2e tests

* Add some unit tests

* Fix remote sync settings update when creating new branch

* Isolate git config for initial import conflict test cases

* Report conflicts on transforms/snippets/lib

[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)

Co-authored-by: edpaget<ed@metabase.com>

* fixup! store conflicts in remote-sync-task table

* fixup! make conflict checking spec driven

* fixup! tests failures

* fixup! lints

* fixup! exclude tags from conflict

* Fix unintended changes from merge in RemoteSyncSettingsForm.tsx

* Address PR comments

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
2026-02-11 03:37:38 +00:00
Anderson
70878781e4 Allow adding segments and measures to hidden tables (#69373) 2026-02-11 00:37:11 -03:00
github-automation-metabase
d4229d9cd8 Auto-update documentation for master (#69396)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-10 19:21:57 -08:00
John Swanson
00c573febe Report conflicts on transforms/snippets/lib (#68506)
* Report conflicts on transforms/snippets/lib

[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)

Co-authored-by: edpaget<ed@metabase.com>

* fixup! store conflicts in remote-sync-task table

* fixup! make conflict checking spec driven

* fixup! tests failures

* fixup! lints

* fixup! exclude tags from conflict

* fixup! don't delete builtins

* fixup! ignore built-in tags

* fixup! preserve built-in python library

* fixup! kondo

* fixup! correct condition

* fixup! module sort

* fixup! build where clause for post-import removal

* fixup! ws

* fixup! pythonlibrary in serialization tests

---------

Co-authored-by: Edward Paget <ed.paget@gmail.com>
2026-02-10 23:35:21 -03:00
Anderson
6602db9fd2 Implement Archived Snippets page (#68823)
* Implement archived snippets page / Adjust archive/unarchive actions for snippets and folders

* Add more coverage

* Fix ts

* Fix ts / Fix e2e test

* Fix eslint/prettier

* Fix e2e test

* Remove empty file
2026-02-10 22:33:40 +00:00
John Swanson
78d36e43e4 Do not allow publishing tables without query perms (#69171)
* Do not allow publishing tables without query perms

Publishing a table changes query permissions. So you shouldn't be able
to publish a table that you don't have query permissions on, and then be
able to query it.

* fns for `can-publish?`, `can-publish-all-table?`

* switch to `library` ff
2026-02-10 14:28:38 -08:00
John Swanson
88a769d9a8 Unify table visibility with can-query semantics (#69199)
* Unify table visibility with can-query semantics

Table visibility checks had drifted across different APIs.

- `(can-query? table)` checked whether you had view access
and create-queries access OR the table was published. This is incorrect:
the table is queryable if you have view access AND either the table is
published OR you have create-queries.

- the collections API included tables that were not queryable.

- the search API allowed you to view tables if a) you had data
permissions on the table, AND b) the table was unpublished or published
in a collection you had access to. This is incorrect, since publishing a
table shouldn't hide a previously visible table from search results.
Search should return tables for which you have view-data permissions
PLUS the table is either published or you have create-queries
permissions.

Fundamentally this change:

- correctly defines what `(can-query? table)` means, and
- uses that new definition of `can-query` to determine table visibility
  across the collection, search, and table APIs.

Note that I did not change some existing usages of
`(mi/visible-filter-clause :model/Table ...)`, which will continue to
exclude tables for which the user does not have explicit data
permissions set (but could otherwise query due to being published). That
should be a simple followup PR.

- align SQL table visibility with mi/can-query? semantics for search paths

- add enterprise `published-table-visible-clause` and wire optional

- `published-via-collection` support into `(mi/visible-filter-clause :model/Table ...)`

- update search table fallback permission check to use canonical `mi/can-query?`

- fix collection table children filtering to include `published-via-collection` queryability

- make `(mi/can-query? :model/Table)` return explicit booleans

- add/adjust EE tests for:
  - published-table SQL clause behavior
  - collection items visibility under view/query perms
  - search visibility when user lacks query perms
  - search visibility for unpublished tables when user has data perms
  - stabilize appdb negation test by avoiding brittle exact count for "customer" in shared index data

* don't use `published-tables` directly

and fix kondo config

* correct feature for library

* kondo

* ensure we bind `*current-user-id*` in search

fallbacks rely on functions that use dynamic vars to check permissions.

Search is designed to use only the search context (with its
`current-user-id` and `current-user-perms`) and binds those dynamic vars
accordingly.

Previously we just needed to bind `current-user-permissions-set` but now
we should also bind `current-user-id` as well.

* fix tests

* correct feature for library
2026-02-10 14:28:21 -08:00
Fraser
4789ed4666 Convert LogoIcon to TypeScript (#69060)
* Convert LogoIcon to TypeScript

Closes DEV-1405

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 09:42:54 +13:00
kevinkelleher12
135d176247 Update table email styles to match frontend (#69176) 2026-02-10 15:20:48 -05:00
Nathan Voxland
43b3ecf3e2 Minor code cleanup (#69236)
Code cleanup
2026-02-10 13:37:28 -06:00
Cam Saul
843350757c Disallow using -rest modules in non-rest modules (#69045)
* Disallow using `-rest` modules in non-rest modules

* Add Kondo linter

* Kondo lint fixes 🔧

* Test fix 🔧
2026-02-10 10:35:33 -08:00
Riley Thompson
0464d028b3 Interrupt threads stuck after query cancellation (#69254)
* interruot stuck threads

* small changes
2026-02-10 13:26:31 -05:00
Jeff Bruemmer
9c9c18d653 docs - fix typo in transforms-enabled setting description (#69353)
Fix typo in transforms-enabled setting description
2026-02-10 18:14:16 +00:00
Maksym Yakubych
38bf8580ea fix: grid Map Pins Offset in PDF Export (#68751) 2026-02-10 12:48:25 -05:00
Nick Fitzpatrick
ce11a50d64 update edit table metadata button link to stay in data studio (#69187) 2026-02-10 13:43:31 -04:00
Chris Truter
b1212ac263 Support transform upserts in Workspace (#69283) 2026-02-10 17:22:37 +00:00
dpsutton
d77f52936e test files trigger module change, workspaces trigger drivers (#69358)
two changes:
- chris changed a file in a workspaces test file and no backend tests
ran at all:

```
=== Module Analysis ===
Changed modules: #{}
Driver module affected: false
Important file changed: false
Drivers with file changes: #{}

=== Driver Decisions ===
h2                        RUN  - H2/Postgres always run
athena                    SKIP - no relevant changes for cloud driver
bigquery                  SKIP - no relevant changes for cloud driver
clickhouse                SKIP - driver module not affected
databricks                SKIP - no relevant changes for cloud driver
druid                     SKIP - driver module not affected
druid-jdbc                SKIP - driver module not affected
mongo                     SKIP - driver module not affected
mongo-ssl                 SKIP - driver module not affected
mongo-sharded-cluster     SKIP - driver module not affected
mysql-mariadb             SKIP - driver module not affected
oracle                    SKIP - driver module not affected
postgres                  RUN  - H2/Postgres always run
presto-jdbc               SKIP - driver module not affected
redshift                  SKIP - no relevant changes for cloud driver
snowflake                 SKIP - no relevant changes for cloud driver
sparksql                  SKIP - driver module not affected
sqlite                    SKIP - driver module not affected
sqlserver                 SKIP - driver module not affected
vertica                   SKIP - driver module not affected
```

So we want the workspace module to be marked dirty by this change. It's
currently filtered out by `remove-non-driver-test-namespaces`.

But a follow-on: workspaces run against different dbs and we therefore
want to ensure this not only triggers driver tests, but also cloud db
tests. So a few tests change to ensure this happens, consequent of
adding `enterprise/workspaces` to `modules-triggering-cloud-drivers`.
2026-02-10 11:04:25 -06:00
Edward Paget
f0abb34fe4 fix: better display for transforms sync changes (#68919)
Better display for transform sync changes where we treat toggling the
`remote-sync-transforms` as though we are toggling the
`is_remote_synced` setting on Root transforms collection. This then
creates a 'collection' typed remote sync object entry for the Root
collection and uses that to drive dirty state display (or non-display)
on the frontend.

This object also drives how items are deleted from the sync so when this
'collection' is in a deleted state it removes all transforms related
content from the sync but preserves it locally.
2026-02-10 17:04:13 +00:00
dpsutton
a2a08af4b1 ease how we generate nano-ids (#69317)
* ease how we generate nano-ids

Fixes https://github.com/metabase/metabase/issues/68130

nano-ids are not needed to be secure, they just need to be
distinct. They hide no secrets but assign identity.

In https://github.com/metabase/metabase/pull/66413 we replaced our usage
of https://github.com/zelark/nano-id with encore. These are almost the
same except that encore uses `secure?` to be true by default. In
practice this is:

```clojure
(if secure?
  (com.taoensso.encore.Ids/genNanoId (.get com.taoensso.encore.Ids/SRNG_STRONG) len)
  (com.taoensso.encore.Ids/genNanoId                                            len))
```

And that `com.taoensso.encore.Ids/SRNG_STRONG` is

```java
public static final ThreadLocal<SecureRandom> SRNG        = ThreadLocal.withInitial(SecureRandom::new);
public static final ThreadLocal<SecureRandom> SRNG_STRONG = ThreadLocal.withInitial(() -> {
        try { return SecureRandom.getInstanceStrong(); }
        catch (java.security.NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to initialize strong SecureRandom", e);
        }});
```

the implmentation in the old library was

```clojure
(defonce *secure-random (delay (SecureRandom.)))
```

So passing `false` for the encore version of the nanoid restores the
previous behavior.

CALLOUT:
One thing to call out is that this did slightly change how we generate
nano-ids based on a seed. We used this behavior to backfill
nano-ids. That let us try to ensure that the same thing in multiple
systems would have the same nano-id, thus identifying them across
systems.

We are now generating different nanoids for the same inputs.

```clojure
❯ java -cp $JARS/1.45.4.jar clojure.main
Clojure 1.11.1
user=> (doto 'metabase.util require in-ns)
metabase.util
metabase.util=> (generate-nano-id "cafebabe")
"VlXdQMzunVywNw_SArkKX"
metabase.util=>
```
This is a consistent nanoid all the way up to 57:
```clojure
❯ java -cp $JARS/1.57.10.jar clojure.main
Clojure 1.12.2
user=> (doto 'metabase.util require in-ns)
metabase.util
metabase.util=> (generate-nano-id "cafebabe")
"VlXdQMzunVywNw_SArkKX"
metabase.util=>
```

And now is different in 58:

```clojure
❯ java -cp $JARS/1.58.3.jar clojure.main
Clojure 1.12.3
user=> (doto 'metabase.util require in-ns)
metabase.util
metabase.util=> (generate-nano-id "cafebabe")
"xNzFsobWPxaYpY0ucTMmz"
```

This is not a problem because we backfilled these nanoids in ~41 or so
and no longer allow anyone to save a model without one. But is worth a
callout that 58 changed this.

* fix drivers team attribution (#69323)

causes module config tests to fail
2026-02-10 11:03:33 -06:00
Jeff Bruemmer
33a572f9a6 docs - handleLink in mod embeds (#69255) 2026-02-10 12:01:55 -05:00
Nathan Voxland
89bb889883 Added MB_MONITOR_PERFORMANCE option (#69298) 2026-02-10 10:59:03 -06:00
Jeff Bruemmer
8e33138caf docs - embedded alerts (#69201)
* embedded alerts

* Apply suggestion from @jeff-bruemmer
2026-02-10 11:58:07 -05:00
Fraser
355a5fc29c Use bun package manager (#68170)
* Use bun in package.json

* Update workflows

* Update more workflows

* Kick ci

* Fix yaml

* Fix type errors

* Compat with snyk

* Fix jest resolutions

* Add another esm package

* Fix aliases and next js missing deps

* Update next js embed tests

* Try fix embed test config

* Fix

* Fix requires in e2e support

* Use bun not yarn in embed bin

* Revert config changes

* Use bun in more scripts and use prepare-release action

* Replace more yarn usages

* Remove overrides from bunfig move to package json

* Revert e2e support changes

* Add back comment

* [ci skip] comment typo

* Update bun lock

* Update to reference bun

* Update to reference bun

* Update license disclaimer

* Tidy tests

* Update to use bun in workflows

* Change aliases

* Update codemirrort selector

* Tidy license generation

* Remove .only

* Fix yarn references

* Checkout .github for release scripts

* Update lockfile

* Re-add package

* update release bunlock

* fix checkout check

---------

Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-02-10 16:27:57 +00:00
github-automation-metabase
50241cb516 Auto-update documentation for master (#69326)
* Update generated docs (master)

* Apply suggestion from @jeff-bruemmer

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-10 16:01:40 +00:00
Braden Shepherdson
3fcac725b2 [QP] Properly escape SQL LIKE metachars for :contains and friends (#67665)
Fixes #67075.

`:starts-with`, `:contains` and `:ends-with`, which use SQL `LIKE`
clauses on SQL databases, were previously using the literal string from
the user directly, without escaping the `LIKE` metacharacters `%`, `_`
and backslash.

This change adds a new `sql.qp` multimethod to the driver API, with a
basic implementation that uses backslashes and works for Postgres,
MySQL/Maria and H2. SQL Server supports escaping via regex-style `[%]`
character classes.

Oracle and SQLite need an explicitly set `LIKE '...' ESCAPE '\'` clause.
I'm leaving that for a future PR since it requires refactoring how the
`LIKE` clauses are constructed more deeply.

Updates the driver changelog, though fortunately the default case should
work for most drivers. Not to be backported, because of the driver API
change.
2026-02-10 15:26:27 +00:00
Nemanja Glumac
e2e2c70165 Fix containerize-uberjar workflow failing on pull requests (#69346)
The workflow was using `github.sha` (the merge commit SHA) when fetching
artifacts, but the uberjar workflow uploads artifacts using the PR head
commit SHA (`github.event.pull_request.head.sha`). This mismatch caused
the containerize workflow to fail with "artifact not found" errors.

Added `github.event.pull_request.head.sha` to the fallback chain in three
places: the artifact fetch commit, the GIT_COMMIT_SHA build arg, and the
Trivy scanner checkout ref.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 16:08:06 +01:00
Timofey Kachalov
df0622c46a Move some logic from translateColumnDisplayName to CLJ lib side (#69005) 2026-02-10 18:45:50 +04:00
Nemanja Glumac
05ab4e7919 Resolve CVE-2026-25639 (#69340)
Even though this vulnerability does not affect our production code,
it was easy to resolve `axios` to the patched version.
2026-02-10 07:15:43 -07:00
Nicolò Pretto
b8ad77a580 fix Back button on eajs browser component (#69273)
* wip

* Revert "wip"

This reverts commit a4dbdef16c.

* cleanup

* fix bug when clicking on breadcrumbs

* clean up old type

* Update frontend/src/embedding-sdk-bundle/components/private/SdkInternalNavigation/SdkInternalNavigationProvider.tsx

Co-authored-by: Phoomparin Mano <poom@metabase.com>

* jsdoc for virtual

---------

Co-authored-by: Phoomparin Mano <poom@metabase.com>
2026-02-10 13:14:09 +00:00
Nicolò Pretto
22c7912005 export InteractiveQuestion.NavigationBackButton and deprecate the old one (#69292)
* export `InteractiveQuestion.NavigationBackButton` and deprecate
`InteractiveQuestion.BackButton`

* jsdoc

* more jsdoc

* add test
2026-02-10 12:32:18 +01:00
Chris Truter
6c73d0a9d4 Return WS api key when it's created (#69333) 2026-02-10 12:48:58 +02:00
Sébastien
084e3ea6df fix(SDK): fixed bugged scrolling in embedded metabot (second version) (#69265)
* fixed bugged scrolling in embedded metabot

* focus

* .

* e2e test
2026-02-10 11:43:36 +01:00
Chris Truter
2957fc98c6 Allow workspace user to archive its own workspace (#69288) 2026-02-10 10:38:58 +00:00
Chris Truter
3286107b15 Ad hoc query API for workspaces (#69274) 2026-02-10 12:33:56 +02:00
Chris Truter
fb97c31b6b Run-stale-ancestors option for workspace transform execution (#69281) 2026-02-10 09:46:13 +00:00
Stas Gavrylov
9529117f1e GDGT-1668: Migrate notifications to TypeScript (#69104)
* Update Claude instructions

* Some DashboardSubscription type usage refactoring

* Migrate SendTestPulse to TS. Introduce DashboardSubscriptionData. Related refactoring

* Migrate ArchivePulseModal to TS

* Migrate UnsubscribePulseModal to TS

* Migrate ArchiveModal and test

* Migrate to TS: UnsubscribeModal. Related refactoring

* Migrate to TS: Notifications actions and routes

* Migrate to TS: ModalRoute refinement

* Fix eslint

* Adjust types of ModalRoutecomponents

* Fixes following bot code review

* Some more type refinement

* Address PR comments

* More fixes/refactoring

* Update route files. Convert to components

* Rename ArchiveNotificationModal to avoid confusion with collections. Fix export

* Fix more exports. Remove type casting. Add Response type guard

* Refactor routes back to getter functions

* Add early return for modals rendering. Add isObject in type-guard

* Refine Response type-guard
2026-02-10 10:41:53 +02:00
Nemanja Glumac
cb119f840b Add auto-detection of changed Loki stories for stress testing (#68951)
* Add auto-detection of changed Loki stories for stress testing

Enable the Loki stress test workflow to automatically trigger on PRs
that modify .stories.tsx files and detect which stories to test based
on git diff. Manual workflow_dispatch still works with optional filter
override.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 09:02:48 +01:00
dpsutton
551108d317 fix drivers team attribution (#69323)
causes module config tests to fail
2026-02-09 21:23:37 -06:00
Fraser
9c5b714279 Convert LegendActions to TypeScript (#69065)
Closes DEV-1410

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 15:05:46 +13:00
Maksym Yakubych
19d9dcb047 feat: allow empty min and max for scalar conditional colors (#69177) 2026-02-09 20:34:18 -05:00
Fraser
13a641e649 Convert ViewSidebar to TypeScript (#69070)
* Convert ViewSidebar to TypeScript

Closes DEV-1415

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 20:20:39 -05:00
Fraser
c5fe906f7b Convert ViewLeftSidebarContainer to TypeScript (#69068)
Closes DEV-1413

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 20:20:12 -05:00
Riley Thompson
045a331f78 Update querying team and remove drivers (#69307)
update querying team, remove drivers
2026-02-09 23:01:01 +00:00
Nick Fitzpatrick
5602bcee19 updating upsell CTA links (#69308) 2026-02-09 18:43:26 -04:00
Nick Fitzpatrick
30b32c0c7f Uxw 2973 admin toggle for transforms global (#69240)
* enable page

* update permission functions, add transformsEnabled check

* hook up button

* temp

* add unit tests for transform layout page

* adjusting unit tests for permissions graph

* adjust e2e tests

* temp

* updating checks in e2e tests

* adding missing route mocks to unit test

* now the test should work

* do not export transforms-enabled

* adjust transforms e2e test

* update selectors to be a bit more clear

* additional tests
2026-02-09 18:42:52 -04:00
Nick Fitzpatrick
976f73531b update AllChangesView unit tests (#69313)
* update AllChangesView unit tests

* removing unneeded test
2026-02-09 17:52:42 -04:00
Jeff Bruemmer
98d8aef4f0 docs - embed translations (#69196) 2026-02-09 21:50:32 +00:00
Nathan Voxland
f3e1558740 Don't use the deprecated enable-query-caching value (#69256)
Don't use the deprecated enable-query-caching value which may have been stored as "false" in the database.
2026-02-09 14:21:23 -06:00
Edward Paget
aa7f30169f feat: snippets under 'library' in changes view (#68910)
Display dirty snippets and snippets collections as children of the
library collection in the list of dirty changes for push.
2026-02-09 12:48:52 -06:00
Nathan Voxland
c5c1d2424d Allow data-analysts to call GET /api/user (#69033) 2026-02-09 11:52:41 -06:00
Fraser
744ba25909 Convert Grid to TypeScript (#69058)
* Convert Grid to TypeScript

Closes DEV-1403

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:19:44 -07:00
kevinkelleher12
4c6d90cf00 Fix infinite hang caused by selecting drop down in conditional formatting settings (#69141) 2026-02-09 12:07:15 -05:00
Anderson
b6427ea107 Address issues found by Claude review on "Data Studio Upsells" #68886 (#69258)
Address issues found by Claude review
2026-02-09 13:53:12 -03:00
Fraser
530ca1eab1 Convert Warnings to TypeScript (#69066)
Closes DEV-1411

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 16:45:04 +01:00
Timofey Kachalov
c82d33f4b3 Revert temporary FE-side filters content-translation logic (#69276) 2026-02-09 15:42:39 +04:00
Fraser
265438590b Convert DisclosureTriangle to TypeScript (#69057)
Closes DEV-1402

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 20:51:43 +13:00
metabase-bot[bot]
29790430fe [chore] Update E2E test timings with recent data (#69269)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-09 11:50:52 +13:00
Fraser
30a8a97d84 Convert PermissionsEditorEmptyState to TypeScript (#69053)
Closes DEV-1398

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:12:17 +13:00
Fraser
c7c20bfb12 Convert GlobalFingerprint to TypeScript (#69078)
* Convert GlobalFingerprint to TypeScript

Closes DEV-1423

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:12:01 +13:00
Fraser
04c6381858 Convert LoadingAndGenericErrorWrapper to TypeScript (#69063)
Closes DEV-1408

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:11:45 +13:00
Fraser
2af98ce335 Convert TableSidebar to TypeScript (#69088)
* Convert TableSidebar to TypeScript

Closes DEV-1433

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:11:14 +13:00
Fraser
6c3a3b99ca Convert BaseSidebar to TypeScript (#69089)
* Convert BaseSidebar to TypeScript

Closes DEV-1434

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:09:53 +13:00
Fraser
71e21281bb Convert SegmentFieldSidebar to TypeScript (#69090)
* Convert SegmentFieldSidebar to TypeScript

Closes DEV-1435

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:09:25 +13:00
Gabriel Moreno
5458b8ae50 Data Studio Upsells (#68886)
* feat: add new gem & pattern backgrounds for upsell page

* feat: use new upsell designs

* feat: bring app switcher & enhance designs

* feat: create `DottedBackground` component

* refactor: purchase page

* fix: pyton transforms upsell condition

* fix: remove unnecessary relative selector

* fix: cta hover states

* fix: border causing layout shift

* fix: draggable decoration lines

* feat: implemnet new designs for remote sync

* refactor: remove DottedBackground from `metabase/ui`

* feat: implement initial in-place trial-up

* feat: use right add-on names for python transforms

* feat: transforms purchase page

* feat: add correct transforms add-ons on api

* reafactor: reorganize upsells code

* feat: python transforms upsell modal

* refactor: reorganize transforms upsell page

* fix: use right add-on

* Move renderTierSelection and renderTierSelection to dedicated components

* remove commented code

* refactor: organize structure properly

* Add some unit tests for transforms upsell

* Add more unit tests

* Clean up

* Fix translatable cost description string / Improve scrolling UX

* Fix copy to make it clear we are charging additional costs

* Fix ts

* Fix tests part 1

* Simplify upsell cost description text

* Fix 1 e2e test

* a few more tested fixed

---------

Co-authored-by: Anderson <anderson@metabase.com>
2026-02-06 20:12:10 -03:00
Riley Thompson
4586ae1efc Allow syncing timestamp_ntz columns in databricks (#67140)
dont exclude timestamp_ntz
2026-02-06 21:48:30 +00:00
Nick Fitzpatrick
7200371783 Scalar viz ensure field to select has a section (#69179) 2026-02-06 17:22:01 -04:00
kevinkelleher12
8e68044b26 Fix "View as table" in visualizer (#69204) 2026-02-06 15:48:24 -05:00
Alexander Polyankin
868b69bc46 Create MBQL queries with the lib in unit and E2E tests (#68719) 2026-02-06 15:47:27 -05:00
Maksym Yakubych
88df5f5a0e fix: prompt suggestions should left-align with the input box (#69227) 2026-02-06 20:42:10 +00:00
Timofey Kachalov
95875a4166 feat(sdk,embed-js): Cover displayed column names with content-translations in additional places (#69192) 2026-02-07 00:42:03 +04:00
Maksym Yakubych
903307c93a fix: the timing of the shimmer loading indicator effect should be 2x as fast (#69239) 2026-02-06 14:41:46 -06:00
Maksym Yakubych
9155352685 chore: move undrfined from ux-west to metabot team in team.json (#69243) 2026-02-06 14:41:18 -06:00
Maksym Yakubych
4a35e01689 fix: dark Theme Hides values in Gauge Chart (#69237) 2026-02-06 14:38:10 -06:00
Maksym Yakubych
378a6384d7 fix: dashboard card becomes uneditable after reordering funnel steps (#69242) 2026-02-06 14:36:22 -06:00
Sébastien
495f4fd395 Guest embedding should use the primary database for queries (#68952)
* Guest Embedding should use the primary database for queries

* make sure user is set to nil for guest embeds

* test

* test

* .

* .

* fixed existing clj test

* fixed existing clj test

* lint

* address comments on unit tests

* using with-database-routing-off

* kondo

* whitespace

* modules order

* addressed comments on tests
2026-02-06 20:27:48 +01:00
Jeff Bruemmer
23831c6fbe docs - note on turning off downloads (#69231) 2026-02-06 18:33:08 +00:00
Nicolò Pretto
4181179942 [feature branch] support internal click behavior with enableInternalNavigation prop in SDK and EAJS (#69117)
* SDK internal navigation: main implementation with context (#68900)

* squashed everything

* Trigger CI

* test ci

* fix accidentally enabling navigation by default

* fix tests

* clean up

* clean up and revert

* fix eslint rule after v9 migration

* idon'trememberanymore

* fix stale closure

* fix button position and more cleanup

* rename to virtual

* fix virtual

* more renaming

* more tests

* more fixes

* more fixes

* more reverts and cleaning up

* remove unused type

* internal navigation: change back button cover on hover (#69122)

* add support for ct to sdk back button (#69219)

add support for tc in back button

* support enable-entity-navigation in EAJS (#69185)

* tests, fixes

* do a real test for guest on a dashboard

* add     "enableEntityNavigation" to types for browser

* Update frontend/src/embedding-sdk-bundle/components/private/SdkInternalNavigation/SdkInternalNavigationProvider.tsx

Co-authored-by: Sébastien <sebastien@metabase.com>

---------

Co-authored-by: Sébastien <sebastien@metabase.com>

* export back button, test that it shows up with title=false, align button (#69222)

* export back button and test it, also test that it shows up with
title={false}

* EMB-1275 map question props to question

* EMB-1278 add last remaining test

* EMB-1299: align back button with save button when drilling

* revert back button changes to keep backward compatibilty

* removed test

---------

Co-authored-by: Sébastien <sebastien@metabase.com>
2026-02-06 17:43:41 +00:00
Nathan Voxland
5fffeb5c62 Allow source-readable to be null in response schema (#69232) 2026-02-06 11:14:09 -06:00
Nicolò Pretto
6a400ce43a feat(modular): support handleLink function (#68418)
* feat(eajs): support handleLink function

* fix unit tests

* rename, remove timeout which caused bugs if host app used alert() or other blocking things

* nest in pluginsConfig as is in the sdk

* put token feature guard

* Revert " put token feature guard"

This reverts commit 4f368ab41e.

* remove isWithinIframe
2026-02-06 17:06:53 +00:00
github-automation-metabase
c0ac8fdce6 Auto-update documentation for master (#69206)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-06 12:04:07 -05:00
Maksym Yakubych
da0f559b55 fix: logo in email is not centered (#68806) 2026-02-06 10:46:44 -06:00
Mahatthana (Kelvin) Nomsawadi
d3f97ef81c Fix broken Metabase icon in SDK banner when using EE with license (#69215)
* Make eslint rule easier to read

* Prevent future misuse of the Metabase logo in the SDK

* Fix wrong Metabase icon on the SDK when using EE build with whitelabel feature

* fix eslint error message
2026-02-06 15:59:01 +00:00
Alex Yarosh
5367b57309 docs: number chart revision and colors (#69207)
* number chart revision and colors

* Optimized 4 images, saved 166.4 KB (48.9% smaller)

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-06 08:59:40 -05:00
John Swanson
2b027c0ed1 JWTs can set tenant attributes (#68562)
* JWTs can set tenant attributes

* use the merge method directly

---------

Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
2026-02-06 13:08:00 +00:00
Kamil Mielnik
8ba4132e42 GDGT-1620 Flaky workspaces test (#69103) 2026-02-06 18:32:55 +07:00
John Swanson
25cd50c5c4 Allow internal users to have perms on tenant colls (#68181)
* Allow internal users to have perms on tenant colls

Notably, this required allowing internal users to list tenants. I think
this is acceptable?

* CR response

* more cr response
2026-02-06 04:17:39 +00:00
github-automation-metabase
c0085e42d5 Auto-update documentation for master (#69148)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-05 18:24:39 -05:00
Alex Yarosh
24649ede3e docs: data studion perms (#69203)
* access

* sneak in some other edits

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-05 22:31:41 +00:00
dpsutton
a3e48f0867 trigger cloud driver tests on certain modules (#69200)
* trigger cloud driver tests on certain modules

Motivating example:
https://github.com/metabase/metabase/pull/68256/changes added some
schemas to transform apis. Transforms run when drivers run. But it
didn't trigger cloud dbs. And of course, there was an issue with
redshift transform tests.

https://github.com/metabase/metabase/actions/runs/21718378450/job/62645866080
is the determine driver skips link:

```
=== Module Analysis ===
Changed modules: #{models transforms}
Driver module affected: true
Important file changed: false
Drivers with file changes: #{}

=== Driver Decisions ===
h2                        RUN  - H2/Postgres always run
athena                    SKIP - no relevant changes for cloud driver
bigquery                  SKIP - no relevant changes for cloud driver
clickhouse                RUN  - driver module affected by shared code changes
databricks                SKIP - no relevant changes for cloud driver
druid                     RUN  - driver module affected by shared code changes
druid-jdbc                RUN  - driver module affected by shared code changes
mongo                     RUN  - driver module affected by shared code changes
mongo-ssl                 RUN  - driver module affected by shared code changes
mongo-sharded-cluster     RUN  - driver module affected by shared code changes
mysql-mariadb             RUN  - driver module affected by shared code changes
oracle                    RUN  - driver module affected by shared code changes
postgres                  RUN  - H2/Postgres always run
presto-jdbc               RUN  - driver module affected by shared code changes
redshift                  SKIP - no relevant changes for cloud driver
snowflake                 SKIP - no relevant changes for cloud driver
sparksql                  RUN  - driver module affected by shared code changes
sqlite                    RUN  - driver module affected by shared code changes
sqlserver                 RUN  - driver module affected by shared code changes
vertica                   RUN  - driver module affected by shared code changes
```

Important part is `Changed modules: #{models transforms}` and `redshift
SKIP - no relevant changes for cloud driver`. This intends to change that.

* update comment
2026-02-05 16:08:43 -06:00
Robert Kosara
0ae4c70ba8 Data Studio docs (#66299)
* First check-in of the initial skeleton

* Minor edits

* Docs: dependency graph (#66562)

* first draft of dependency graph

* few edits

* typo

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* few edits

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* docs - data studio library (#68602)

* library skeleton

* link

* collection perms

* plans blockquote

* table notes

* updates

* remove data editing

* edits

* Apply suggestion from @jeff-bruemmer

* overview

* intro

* transforms links

* links

* docs: transforms updates (#69037)

* intermediate draft

* more transforms

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* edits

* more links

* more links

* more links

* bot comments

* more bot comments, please just give me all at once

* bot needs to shut up

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* docs: Add Dependency diagnostics page (#68928)

* adding dep diagnostics

* Update docs/data-studio/dependency-diagnostics.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-diagnostics.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-diagnostics.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* some edits

* more edits

* typo

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* docs: data structure (#69184)

* draft

* data structure

* description

* it's measures not metrics

* measures not segments

* Apply suggestion from @jeff-bruemmer

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* review

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Abed Habli <154609371+abdhabli@users.noreply.github.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Jeff Bruemmer <jeffbruemmer@gmail.com>
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-02-05 15:24:29 -05:00
William
bf3a0df461 Fix nested if statements (#69144)
If you have an expression with an if statement inside an if statement, the outer if would get desugared to a case
statement, but the inner if would be left untouched.  This makes desugaring also desugar the inner if.
2026-02-05 20:06:31 +00:00
Braden Shepherdson
a609c0466b [deps] Split "supported" entities into analyzable and dependable (#69188)
Fixes QUE-3070.

This splits the vague, dual-purpose `supported-entities` into two:
- those entities which can be depended on, whose dependents get marked
  stale when they're updated (eg. a table during sync)
- those entities which we can analyze, and should check for staleness

I added `:table` to the old `supported-entities` since they're a valid
*upstream* dependency that might needs its downstream dependents to be
marked as stale, and it failed the schema.

The trouble is that we don't run analysis on tables, but the same set of
"supported" types was used to check for what entities need reanalysis.

That led to a chain like this:
- Something changed, and the entity-check job is scheduled immediately.
- It runs, and checks each `supported-entities` for any entity with
  a missing, `stale` or outdated analysis finding.
- That list now includes tables, and since tables are not analyzed none
  of them have entries - so there's apparently lots of work to do!
- On trying to analyze tables, it fails because they're not supported,
  and it silently does nothing.
- But the batch draining logic still thinks the whole batch was used, so
  it reschedules.
- No real progress is getting made, since the tables cannot really be
  analyzed, therefore they never get marked as done.
- Infinite loop spinning forever!
2026-02-05 14:47:33 -05:00
Nathan Voxland
eeea8c5f3f Add metabase_table.transform_id column (#69125)
* Create a metabase_table.transform_id column instead of dynamically populating it from the dependencies

* Fixing tests

* Include transform in table dependencies

* Moved test after merge

* Moved test after merge

* transforms are now oss

* Fixed failing tests

* Review fixes
2026-02-05 11:24:49 -08:00
Anderson
59c9a579f2 Replace 'data-studio' token feature with 'library' (#69040)
* Replace 'data-studio' token feature with 'library' / data_analyst behind advanced permissions (clean git history)

* Fix clj test

* Fix a couple be tests

* Fix e2e test
2026-02-05 16:19:29 -03:00
Nathan Voxland
eb3d3d806b Added schema to transform API responses (#68256) 2026-02-05 13:07:34 -06:00
Nathan Voxland
42d0d35dbd Do a rollback before discard all (#69026)
Do a rollback before discard all, since discard all can't be ran in a transaction.
2026-02-05 13:07:20 -06:00
Nathan Voxland
5d40e0ab95 Correctly select jobs to run based on tags (#69137) 2026-02-05 13:06:59 -06:00
John Swanson
9e980b9315 bugfix for dependency diagnostics error (#68968)
We were calling `perms/visible-database-filter-select` incorrectly. It
takes a minimum permission.
2026-02-05 10:27:19 -08:00
Maksym Yakubych
4b805ef246 feat: add duplicate option in 3 dot menu in a document (#68075) 2026-02-05 15:10:48 -03:00
Noah Moss
0234ce1061 Hide transforms from metabot if source is not readable (#69041)
* Hide transforms from metabot if source is not readable

* test simplification

* fix test nesting

* dedupe transform-ids earlier

* Fix module interface

* Fix rebase - transforms were moved to OSS
2026-02-05 10:59:23 -05:00
Ryan Laurie
bfc4963109 Automate js/ts stats update (#69167)
* automate typescript stats update

* job id

* fix var name

* cleanup

* remove test code
2026-02-05 08:27:30 -07:00
Nick Fitzpatrick
f7336c2068 update copy (#69130)
* update copy

* update e2e tests
2026-02-05 11:15:37 -04:00
dpsutton
04ac52e1d6 make sure database is initialized (#69173)
seeing error in CI:

```
ERROR in metabase.upload.db-test/current-database-test (DbException.java:502)
Uncaught exception, not in assertion.

             clojure.lang.ExceptionInfo: Table "METABASE_DATABASE" not found (this database is empty); SQL statement:
                                         SELECT * FROM "METABASE_DATABASE" WHERE "UPLOADS_ENABLED" = TRUE [42104-214]
```

https://github.com/metabase/metabase/actions/runs/21711162702/job/62620032674

we just need to ensure that the db is initialized first
2026-02-05 09:05:26 -06:00
Roman Abdulmanov
5d745ce4c8 Report tenants usage info to HM (#69009)
report tenants usage info to HM
2026-02-05 14:28:37 +00:00
Nemanja Glumac
c5960b7d9d Add Rosetta 2 detection and installation to dev-install (#69115)
On Apple Silicon Macs, some webpack dependencies (webpack-notifier)
require Rosetta 2 to run x86_64 binaries. Without it, the webpack dev
server fails with "Error: spawn Unknown system error -86".

This adds a check during prerequisites that detects if Rosetta is
missing and offers to install it via softwareupdate --install-rosetta.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 14:22:08 +01:00
da
478b097458 Upgrade jspdf (#69113) 2026-02-05 13:37:24 +01:00
Dan Stone
14d95aaf44 Allow medallion values on read (#69158)
Our migrations can race with writers, this leads to situations
where we might still see values for e.g. an enum according to some prior
schema.

We saw on stats a sync occurred concurrently with the migrations and caused a record with medallion data_layer values to appear _after_ the migration.

Should follow up with a longer term fix without leaving such cruft in the code.
2026-02-05 12:17:41 +00:00
Nemanja Glumac
0d24b395e8 Fix broken containerize workflow (#69156) 2026-02-05 11:23:45 +00:00
Kamil Mielnik
8c0645cc97 GDGT-1585 Update incremental transform warning copy for complex queries (#69109)
Update copy in QueryComplexityWarning
2026-02-05 17:54:39 +07:00
Nemanja Glumac
ee20f35b7f Programmatically list source directories for cloverage (#68955) 2026-02-05 11:18:16 +01:00
Nicolò Pretto
5b8748fda3 feat(modular): support relative paths for jwtProviderUri (#69119)
feat(modular): support relative paths for jwtPRoviderUri
2026-02-05 10:28:12 +01:00
Nemanja Glumac
8143e32165 Unify the JAR artifact naming strategy (#69114) 2026-02-05 10:03:40 +01:00
Fraser
ad9d9d886b Convert List to TypeScript (#69059)
Closes DEV-1404

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 21:24:17 +13:00
Mahatthana (Kelvin) Nomsawadi
2028e4af8c Remove links from all alerts/subscriptions related emails in modular embeddings (#69014)
* Remove link from broken dashboard notification

* Remove links from alerts setup email

* Add tests

* Remove links from unsubscribe email

* Remove links from card change or archived emails

* add tests for card change email notifications

* add tests to the broken dashboard email

* Format

* Remove unused comments

* Improve test util names

* Format again

* Fix name
2026-02-05 05:11:20 +00:00
Fraser
d0f660ba08 Convert Remapped to TypeScript (#69083) 2026-02-05 03:03:30 +00:00
Fraser
7d269ec8cd Convert ReferenceHeader to TypeScript (#69085)
Closes DEV-1430

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:57:42 +13:00
Fraser
d3c44902a1 Convert QuestionSummarizeWidget to TypeScript (#69071)
Closes DEV-1416

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:55:55 +13:00
Fraser
2963e8e325 Convert DatabaseSidebar to TypeScript (#69086)
* Convert DatabaseSidebar to TypeScript

Closes DEV-1431

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:55:36 +13:00
Fraser
2785b1391c Convert SegmentSidebar to TypeScript (#69091)
* Convert SegmentSidebar to TypeScript

Closes DEV-1436

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:41:53 +13:00
Fraser
4e87135f5f Convert ChartSettingColorsPicker to TypeScript (#69094)
Closes DEV-1439

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:41:04 +13:00
Fraser
e27825b087 Convert AccountApp to TypeScript (#69077)
Closes DEV-1422

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:39:08 +13:00
Fraser
4336e7bc1c Convert FieldSidebar to TypeScript (#69087)
* Convert FieldSidebar to TypeScript

Closes DEV-1432

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:38:51 +13:00
Fraser
5ce4289d08 Convert SidebarLayout to TypeScript (#69074)
Closes DEV-1419

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:36:34 +13:00
Denis Berezin
9585b7a065 Move Data Studio common stuff to OSS (#68571)
* Fixing tests

* Fixing tests

* Fixing tests

* Fixing tests

* Fixing tests

* Fixing tests

* Fixing test

* Added source_readable to transform APIs

* Fixing tests

* Starts implementing read-only state for job detail page

* Stubs out potential solution for preventing non-admins from putting jobs into a state where they can no longer edit them

* Troubleshooting failing test

* Shows permissions error on transform page when user doesn't have source-read permissions. Disables run button when user lacks write access.

* Troubleshooting failing test

* Makes TagSection readOnly on job page if user lacks write access on any transforms that'd be run by the job

* Removes unnecessarily duplicated code from ScheduleSection

* Troubleshooting failing test

* Troubleshooting failing test

* Troubleshooting failing test

* Troubleshooting failing test

* Cleanup

* Fix unit tests

* Updates e2e test (group-15)

* Updates e2e tests (transforms-permissions.cy.spec.ts)

* Fixed transform-job permission check

* Only require transform write access for tag selector on job page

* Tweak tag tooltip text

* Prevents deleting/editing tag when it runs a job the user doesn't have transform write access on

* Adds a couple more transforms-permissions e2e tests

* Build transform permission off table can-query

* Added :can_run to transform-tag API

* Updates FE to use can_run on TransformTag

* Code cleanup

* Updates transforms list to disable transform rows the user doesn't have read access for

* Code cleanup

* Fixing test failures

* Fixing test failures

* Fixing test failures

* Fixing test failures

* Merged from master

* Test troubleshooting

* Resolved conflicts

* fixup: Reimplements row disabling in TransformListPage

* fixup: Adds readOnly prop to new IncrementalTransformSettingsWrapper component

* fixup: Reimplements readOnly state for PythonTransformEditor

* Adds read-only state for transform owner section

* Updates recently-moved canAccessDataStudio with canAccessTransforms check

* Updates permission-management unit tests

* Adds tooltip to transform column in permissions table

* Hides tooltip in Transforms column in permissions table if selected group is admin or analysts

* Fix unit test

* Updates some e2e tests that deal with non-admins using transforms to make sure they belong to the analyst group

* Adjusting backend permissions for new logic: all analysists can see transforms they have db access to, transform-permission is for writes

* Code improvements

* Code improvements

* Fixed test

* Fixing tests

* Troubleshooting tests

* Troubleshooting tests

* Fixing tests

* Update e2e tests

* Brought back can_access_transforms

* Fixing tests

* Better python permission checking

* Start, WIP

* Moved Library back to EE

# Conflicts:
#	enterprise/frontend/src/metabase-enterprise/data-studio/library/LibrarySectionLayout/PublishTableModal.tsx
#	frontend/src/metabase/data-studio/data-model/components/TableSection/TableAttributesEditBulk.tsx

* Continue moving Library back to EE

* Hotfix

* Fixing permissions

* Fixing permissions

* Fixing tests

* Fixing tests

* move out transforms api

* Fixing tests

* move transforms to oss

* actually it is true

* cleanup

* Fixing tests

* Fix post-merge ts error

* Close library functionality in OSS, fix some units

* Move oss table api endpoints for data structure, fix more unit tests

* Move oss table api endpoints for data structure, fix more unit tests

* Updates transforms list page so "New" is hidden and "Python library" is disabled if user has no transform permission for any database

* Fix typecheck issues

* Move non-python transform APIs to OSS

* Fix kondo

* Fix EE BE

* Code review fixes

* Code review fixes

* Merge remote-tracking branch 'origin/master' into transforms-permissions

# Conflicts:
#	.clj-kondo/config/modules/config.edn
#	enterprise/backend/test/metabase_enterprise/remote_sync/transforms_test.clj
#	enterprise/frontend/src/metabase-enterprise/transforms/pages/TransformListPage/TransformListPage.tsx

* Code review fixes

* Fixed merge conflict

* Fixed merge conflict

* Fix lint and TS error from merge

* Fix merge issues

* Fix be issues

* Fix some unit tests

* Fix be tests issues

* Fix be tests issues

* Code review fixes

* Allow people with transform permission to see syncable schemas on a db

* code cleanup

* Fix be tests issues

* Fixing permissions

* Fix be tests issues

* Fix prettier

* wip: oss transforms

* fix module order

* fix tests for OSS transforms

* cleanup

* cleanup

* Fix some unit tests

* Fix library for OSS

* fix some more tests

* cljfmt

* add missing placeholder file

* fix more tests

* more tests

* more tests

* deftest-oss into `metabase.test`

* Fix some unit tests

* Fix some unit tests

* Fix transforms upsell for oss

* fix search filter

* fix transforms tables

* fix cycles

* feat: transform setting into collection list (#68758)

* feat: transform setting into collection list

Move the setting for syncing transforms into the list of collections
available to remote sync, so conceptually the transforms root collection
looks like a standard syncable collection.

* Clean up FE a little bit

* undo unneeded changes

---------

Co-authored-by: Anderson <anderson@metabase.com>

* Remove Security and Appearance from embedding settings related links on OSS (#68151)

* feat: enable transform setting on first import (#68807)

* feat: enable transform setting on first import

When a we import a remote that has transforms set the
`remote-sync-transforms` setting to true.

Update the remote sync object table clean up to be driven by the spec
configuration.

Add tests showing that transforms are consistently synced and erased
according to the following rules:

1. if the instance has `remote-sync-transforms` off and local transforms
and the remote does not have transforms content they are preserved after
an import
2. if the instance has `remote-sync-transforms` off and local transforms
and the remote has transforms content, the local transforms are
completely replaced by the remote.
3. if the instance has `remote-sync-transforms` on and the remote has
transforms content any local transforms are completely replaced by the
remote.
4. if the instance has `remote-sync-transforms` on has local transforms,
but the remote has no transforms, the local transforms are removed on import.

* fixup! relocate settings update

* fixup! don't let python libraries clash on import

* fixup! transactions for mysql

* fix: y axis not shown even if it would fit (#68861)

* Deps breaking broken (#68866)

* Add rename /broken to /breaking and add new /broken

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>

* Analysts can do crud on segments and measures (#68501)

* Data Analyst CRUD on measures/segments

Data analysts with unrestricted view-data permissions on a table can now
create, update, and delete segments and measures for that table
(previously superuser-only).

`can-read?` was already granted by the `manage-table-metadata` permission.

Add permission tests for `can-write?` and `can-create?` methods.

* Remove `brand-light` and `brand-lighter` (#68290)

* brand key adjustments

* loki tests

* handle the forgotten brand-dark

* Update Loki Snapshots

* removing brand-hover from dynamic-css-vars

* Adjustments to calendar picker colors

* small adjustments on the permissions pages

* sdk: remove background-hover tests from sdk as dynamic css derives are replaced with color-mix

* stupid spelling

* building shared resources

* Adjusting unit test, loki images

* rebasing adjustments

* Update Loki Snapshots

* small color fixes while I wait for loki

* re-adding highlighted class

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>

* Fix empty Python Library not showing placeholder/comment (#68826)

* CI: query-processor module should trigger driver tests (#68877)

* Delete fuzzing workflow (#68880)

* fix(sdk): fix failing tests for white-labeled colors (#68790)

* Dependency diagnostics sidebar updates (#68825)

* Use getter function to move element (#68714)

* Fix cloud implicit join tests (#68762)

A previous pr broke some tests on master, and this fixes them.

* feat(sdk, embed-js): Add an alerts support to modular embeddings (#68777)

* Add an alerts button on the SDK (#67796)

* Prepare to add alerts to SDK

* Remove unrelated prop from storybook

* Add basic alerts button

* Only show alerts button with the proper flag

* Prevent download button from being shown without proper flag

* use CSS to hide things instead of JS

* Properly position all question buttons

* Use JS to hide empty divs as pure CSS is impossible

* Render alert modal ✌️

* Fix type

* Add todo

* Structure the components better

* Control alert modal state

* Add interactive question storybook

* Make interactive and static question button styles consistent

* Add alerts modal to interactive question

* Make alert button works with custom layouts

* Fix tests

* Fix unit tests

* Fix import order issue

* Remove outdated comment

* Add the same condition to display alert button from the core app

* Polish

* Modify question storybooks to show a question instead of a model

* Hide empty elements more reliably

* Add more conditions to display alert button

* Remove unused `classNames` prop

* Use the same style as the interactive question one

* Remove outdated diff

* Fix alerts button not working in custom layouts

* Remove another unused code

* Add a basic test

* Add unit tests

* fix visibility logic

* Fix E2E tests

* Make assertion on static question tests better

* Improve assertions

* Add interactive question unit tests

* Add e2e test for static question

* Add interactive question e2e tests

* Fix subcomponent

* clarify comment

* Hide other channels than email on the alert modal (#68184)

* Hide channel options on alerts modal

* Add unit tests

* Make the test name clearer

* Fix can't view created notifications the first time (#68197)

* Fix can't view created notifications

* Add tests

* Remove unnecessary return type

* Add a safety guard

* Hide Alert (and download) button on edit mode (#68189)

Hide some buttons on edit mode as it makes no sense there

* Alerts polishing (#68477)

* Misc. improvements

* Make it typesafe

* Add alerts to modular embedding (#68286)

* Add the option in modular embedding wizard

* Support `withAlerts` in modular embedding

* Close the modal after hiding the alert button

* Add E2E tests

* Fix type

* Fix `withAlerts` not working on modular embedding with `drills: false`

* It's 2026!

* 1 plugin to rule 'em all!

* Fix E2E after merging master

* Fix test name

* Add alerts analytics (#68531)

* Add alert setup analytics

* Track withAlerts on modular embedding

* Update snowplow schema

* Fix E2E tests

* Fix schema version

* Remove links from alerts test email (#68547)

* Remove links from alerts template

* Remove links from alert email computed part

* Add tests

* Make embedding util easier to use

* Make alerts and subscriptions payload lighter

* Remove unexpected pprint

* Remove links from alert email via tasks (#68610)

* Save notification card's disable_links when creating

* Add tests

* make bin/mage run-tests able to run a single test (#67450)

* Add content translations for aggregations (#68733)

* fix: typecheck

* oops, add missing file

* fix upload impl tests

* Move upsells to ee for transforms

* fix search tests

* fix mage tests

* fix audit perms

* fix `user->tenant-collection-and-descendant-ids`

* reorganize transform permissions

* fix cyclic dep

* add forgotten test file

* fix modules tests / kondo

* another module config fix

* Fix python transforms upsell in oss, fix unit tests

* fix more tests

* one more test

* one more

* Fix e2e tests

* one more

* and a few more

* oops, syntax error

* fix more tests

* kondoooooo

* dumb test: try increasing latch timeout

* hopefully actually fix h2 oss test

* Fix flaky e2e tests

* Fix lint

* Trigger rebuild

* Fix CI

* Fix CI

* Fix failing e2e test

* fix check for is-data-analyst

* Gate transforms based on `:hosting` flag

* move noop events

* Remove unnecessary `check-permissions-for-model`

* use transform feature gating in `can-read?`

* cr resp: moving tests around

* add `enabled-source-types-for-user` and use it

* remove last `deftest-oss` usage

also clean up kondo config:

- no longer define custom expansions for old macros that no longer exist
- remove `deftest-oss`

* change owner to UX west

* use `is-data-analyst?` and `check-data-analyst`

... in a few more places, instead of manual `(or api/*is-superuser?* api/*is-data-analyst?*)`

* Fixes for BE after merge

* Integrate Workspaces code

* Fixes for BE

* Fixes for BE

* Fixes

* remove unnecessary `when-ee-evailable`

also that typo is driving me up the wall and I'm going to need to fix
it :grimace:

* transforms doesn't use config

* missing import

* fix tests

* kondoooo

* last be test failure?

* fix feature gating for workspaces transforms API

why do we have a separate workspaces transforms API

* kondo

* two more tests

* tests

* couple more tests

* almost... there

* fix a flaky transform run test

this was failing locally because I already had enough transform runs to
fill up the page. simple helper to clean up the transform runs that
exist before running the test, then restore them.

* fix data-model.shared.cy.spec.ts

---------

Co-authored-by: Nathan Voxland <nathan@metabase.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
Co-authored-by: Aleksandr Lesnenko <alxnddr@gmail.com>
Co-authored-by: John Swanson <john.swanson@metabase.com>
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Anderson <anderson@metabase.com>
Co-authored-by: kevinkelleher12 <kevin.kelleher@metabase.com>
Co-authored-by: Maksym Yakubych <undrfined@gmail.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Co-authored-by: bryan <bryan.maass@gmail.com>
Co-authored-by: Fraser <fraser@metabase.com>
Co-authored-by: Phoomparin Mano <poom@metabase.com>
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: William <william@metabase.com>
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
Co-authored-by: Oleksandr Solovyov <alexander@solovyov.net>
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-02-05 02:30:18 +00:00
Fraser
b3f643fad6 Convert CollectionName to TypeScript (#69082) 2026-02-05 15:27:04 +13:00
Maksym Yakubych
2d3ed1861c fix: mini picker loader style (#69027) 2026-02-04 15:17:10 -08:00
John Swanson
beb2b5b751 Change permission required to view segment (#67855)
I think this permission makes more sense and is probably what we
intended. Note that users without `manage-table-metadata` but with table
permission can already read this information from the
`/api/query_metadata` endpoint.
2026-02-04 22:26:25 +00:00
dpsutton
b5ef6e1d0c module test runner (#69124)
* module test runner

support for `:module` and `:modules` syntax for our test runner

When using multiple with `:modules` need to put them in a vector, and
for shell reasons need to quote it. So there's a convenience method
where you just pass an individual:

```shell
clj -X:dev:ee:ee-dev:test :modules '[tiles enterprise/agent-api]'
clj -X:dev:ee:ee-dev:test :module enterprise/agent-api
```

REPL
===

```clojure
test-runner=> (metabase.test-runner/find-and-run-tests-repl
                {:modules '[tiles enterprise/agent-api]})
Running tests with options {:mode :repl, :namespace-pattern #"^(?:(?:metabase.*)|(?:hooks\..*))", :exclude-directories [".clj-kondo/src" "classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :only ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")}
Running tests in ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")
Looking for test namespaces in directory test/metabase/tiles
Looking for test namespaces in directory enterprise/backend/test/metabase_enterprise/agent_api
Finding tests took 159.0 ms.
Running 32 tests
Running before-run hooks...

LONG TEST in metabase-enterprise.agent-api.api-test/get-metric-details-test
Test took 3.447 seconds seconds to run
Ran 32 tests in 6.506 seconds
129 assertions, 0 failures, 0 errors.
{:test 32, :pass 129, :fail 0, :error 0, :type :summary, :duration 6505.825875, :single-threaded 20, :parallel 12}
Ran 12 tests in parallel, 20 single-threaded.
Finding and running tests took 6.7 s.
All tests passed.
Running after-run hooks...
Running QP tests against these drivers: #{:h2}
{:test 32,
 :pass 129,
 :fail 0,
 :error 0,
 :type :summary,
 :duration 6505.825875,
 :single-threaded 20,
 :parallel 12}
```

CLI
===

multiple:
```shell
❯ clj -X:dev:ee:ee-dev:test :modules '[tiles enterprise/agent-api]'
Warning: environ value /Users/dan/.sdkman/candidates/java/current for key :java-home has been overwritten with /Users/dan/.sdkman/candidates/java/21.0.2-tem
Reflection warning, clojurewerkz/quartzite/triggers.clj:85:6 - call to method forJob on org.quartz.TriggerBuilder can't be resolved (argument types: unknown).
Reflection warning, clojurewerkz/quartzite/scheduler.clj:254:3 - call to method checkExists on org.quartz.Scheduler can't be resolved (argument types: unknown).
Reflection warning, macaw/walk.clj:47:5 - call to method walk on com.metabase.macaw.AstWalker can't be resolved (argument types: unknown).
Running tests with options {:mode :cli/local, :namespace-pattern #"^(?:(?:metabase.*)|(?:hooks\..*))", :exclude-directories [".clj-kondo/src" "classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :exclude-tags [:metabot-v3/e2e], :only ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")}
Running tests in ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")
Looking for test namespaces in directory test/metabase/tiles
Looking for test namespaces in directory enterprise/backend/test/metabase_enterprise/agent_api
Finding tests took 11.8 s.
Running 32 tests
Running before-run hooks...

 0/32     0% [                                                  ]  ETA: --:--Placeholder until other changesets
LONG TEST in metabase-enterprise.agent-api.api-test/get-metric-details-test
Test took 10.536 seconds seconds to run

32/32   100% [==================================================]  ETA: 00:00

Ran 32 tests in 18.556 seconds
129 assertions, 0 failures, 0 errors.
{:test 32, :pass 129, :fail 0, :error 0, :type :summary, :duration 18555.859333, :single-threaded 20, :parallel 12}
Ran 12 tests in parallel, 20 single-threaded.
Finding and running tests took 30.4 s.
All tests passed.
Running after-run hooks...
Running QP tests against these drivers: #{:h2}
```

individual:

```
❯ clj -X:dev:ee:ee-dev:test :module enterprise/agent-api
Warning: environ value /Users/dan/.sdkman/candidates/java/current for key :java-home has been overwritten with /Users/dan/.sdkman/candidates/java/21.0.2-tem
Reflection warning, clojurewerkz/quartzite/triggers.clj:85:6 - call to method forJob on org.quartz.TriggerBuilder can't be resolved (argument types: unknown).
Reflection warning, clojurewerkz/quartzite/scheduler.clj:254:3 - call to method checkExists on org.quartz.Scheduler can't be resolved (argument types: unknown).
Reflection warning, macaw/walk.clj:47:5 - call to method walk on com.metabase.macaw.AstWalker can't be resolved (argument types: unknown).
Running tests with options {:mode :cli/local, :namespace-pattern #"^(?:(?:metabase.*)|(?:hooks\..*))", :exclude-directories [".clj-kondo/src" "classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :exclude-tags [:metabot-v3/e2e], :module enterprise/agent-api, :only ("enterprise/backend/test/metabase_enterprise/agent_api")}
Running tests in ("enterprise/backend/test/metabase_enterprise/agent_api")
Looking for test namespaces in directory enterprise/backend/test/metabase_enterprise/agent_api
Finding tests took 12.6 s.
Running 19 tests
Running before-run hooks...

 0/19     0% [                                                  ]  ETA: --:--Placeholder until other changesets
LONG TEST in metabase-enterprise.agent-api.api-test/get-metric-details-test
Test took 11.252 seconds seconds to run

19/19   100% [==================================================]  ETA: 00:00

Ran 19 tests in 19.122 seconds
105 assertions, 0 failures, 0 errors.
{:test 19, :pass 105, :fail 0, :error 0, :type :summary, :duration 19122.404791, :single-threaded 19}
Ran 0 tests in parallel, 19 single-threaded.
Finding and running tests took 31.8 s.
All tests passed.
Running after-run hooks...
Running QP tests against these drivers: #{:h2}
```

* very opinionated
2026-02-04 15:40:51 -06:00
Phoomparin Mano
de1fb87ba1 Add onboarding stepper component for embedding data permissions onboarding (#68801)
* add onboarding accordion

* add storybook for onboarding accordion

* fix the hover color of accordion

* chore: remove unused scrollListItemIntoView

* cleanup accordion

* add onboarding stepper instead

* retain checked icon in selected steps

* remove active step

* add unit tests for accordion

* rename step label to step number

* remove stepper root

* remove explicit ref

* refactor: simplify styles

* simplify storybook

* auto advance stepper

* support locked steps

* auto-infer step number

* remove forwardRef

* do not provide defaults for completed and locked steps

* add horizontal padding to match 64px in design

* style fixes to match design

* address reviews on scroll refs

* fix inconsistent scroll state
2026-02-04 21:18:27 +00:00
Phoomparin Mano
72c578bfdc Remove old llms.txt superseded by Jekyll plugin on docs site (#69132)
remove llms.txt and llms-embedding-full.txt superseded by Jekyll build plugin
2026-02-05 04:57:01 +08:00
Edward Paget
13389939e4 fix: dependency check for snippet eligibility (#69024)
* fix: dependency check for snippet eligibility

* fixup! rename eligibility function
2026-02-04 20:53:19 +00:00
appleby
8824365c61 Remove metabase.llm.costs (#69043)
Rather than providing a best-effort estimate that is likely to get stale, just report 0.0 for the estimated cost.

https://github.com/metabase/metabase/pull/68929#discussion_r2761321583
2026-02-04 11:25:05 -08:00
da
52c03c5b8a Fix formatting and spacing in quartz.properties. Add check in intervals to clusters (#68983)
Fix formatting and spacing in quartz.properties

Adding a new line for Quartz to check in on clusters
2026-02-04 15:54:52 -03:00
Alexander Polyankin
e10dfc7cfc Extract UI components for QB filter widgets (#69051) 2026-02-04 18:41:19 +00:00
github-automation-metabase
8d5a4f6804 Auto-update documentation for master (#69048)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-04 13:21:20 -05:00
Jakub Chodorowicz
ce6d00430d Gdgt 1298 act on e2e code duplication of admin metadata and data (#68600) 2026-02-04 18:35:20 +01:00
Eric Normand
7017eb7941 [Mutation Testing] Kill mutations in metabase.lib.page/page (#69019)
* [Mutation Testing] Add tests for metabase.lib.page/page
2026-02-04 11:03:14 -06:00
Eric Normand
57f23cf311 [Mutation Testing] Kill mutations in metabase.lib.segment/check-segment-overwrite (#68981)
* [Mutation Testing] Add tests for metabase.lib.segment/check-segment-overwrite
2026-02-04 11:02:46 -06:00
Timofey Kachalov
9bacef5fc1 feat(sdk, embed-js): Add joined tables/temporal/bins content translations for aggregations and breakouts and question title (#68954) 2026-02-04 19:09:25 +04:00
Nick Fitzpatrick
5bd8b24794 Only show an app switcher in the dependency page, not the tabs (#68966)
* Only show an app switcher in the dependency page, not the tabs

* fix unit test
2026-02-04 10:54:57 -04:00
Braden Shepherdson
fb225582a8 [Athena] Correctly recognize :base_type when db type is uppercase (#68369)
Athena's JDBC driver returns type names with the same capitalization as
the user types into the admin interface, but the
`sql-jdbc.sync/database-type->base-type` implementation for Athena only
recognized lower-case names (which are the defaults, I gather).

I think most databases don't have this problem, since they ignore the
case you typed in e.g. `CREATE TABLE` statements and have the JDBC
driver always return the canonical spelling of the type names.
2026-02-04 14:39:14 +00:00
Nick Fitzpatrick
c34013f4ff updating color for .SecondaryCTALink (#68001)
* updating color for .SecondaryCTALink

* light and dark upsell themes

* faster storybook build maybe?

* fix types, undo storybook changes

* Update Loki Snapshots

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-02-04 10:32:49 -04:00
Braden Shepherdson
cb62b19dd6 [deps] When Table Metadata is edited, re-analyze all dependents (#68683)
Fixes QUE-3000.

When either the table metadata or field metadata is edited, this runs
the analysis. Since only some metadata changes can impact the analysis,
this is over-sensitive and runs sometimes when it doesn't need to.
2026-02-04 09:21:20 -05:00
Kamil Mielnik
d08614d4d2 GDGT-1658 Unskip custom columns repro (#69097) 2026-02-04 20:38:06 +07:00
Sébastien
5558eeabed feat(sdk, embedjs): support saving and editing questions created with metabot (#68950)
* support saving and editing questiosn created with metabot in SDK/EAJS

* EAJS

* added schema types

* e2e test

* addressed PR comments
2026-02-04 14:36:16 +01:00
github-automation-metabase
f5942dae77 [chore] Update llms.txt for master (#69102)
Update llms.txt and llms-full.txt (master)

Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.

🤖 Generated automatically by llms-txt-generate workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-04 10:53:59 +00:00
Fraser
c8d1566e3c Convert routes-embed to TypeScript (#69092)
Closes DEV-1437

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:17:53 +13:00
Fraser
ad356ffe36 Convert routes-public to TypeScript (#69093)
Closes DEV-1438

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:17:32 +13:00
Fraser
823559542c Remove unused eslintrc files (#69098) 2026-02-04 22:14:02 +13:00
Jakub Chodorowicz
f7801bbc47 feat: change data layer medallion inspired values to hidden, internal and published (#66330)
Change medallion values to hidden/internal/published. Hidden inherits visbility_type = hidden behaviour, internal/final are label only for now.

---------

Co-authored-by: Dan Stone <wotbrew@gmail.com>
2026-02-04 09:13:31 +00:00
Sloan Sparger
9eebf22cbc [Typescript] Convert files that need no changes (#68321) 2026-02-04 21:55:43 +13:00
Nemanja Glumac
cf48b132de Fix jest-haste-map duplicate manual mock warning (#68993)
Jest's haste map uses filenames (without extensions) as identifiers for
manual mocks. Both ExplicitSize and NativeQueryEditor had `__mocks__/index.ts`
barrel files, causing a collision on the name "index".

Fix by removing the barrel files and using explicit require() calls in
register-visualizations.js to point directly to the uniquely-named mock
files (ExplicitSize.tsx and NativeQueryEditor.jsx).

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:58:33 +07:00
Nemanja Glumac
12f5000d9f Fix broken Link mock (#68995)
The fix was changing the mock from returning a function directly (which
would be a default export) to returning an object with a Link property
(named export), matching how the actual module exports the component.
2026-02-04 14:47:39 +07:00
Alexander Polyankin
db53feb9ab Hydrate root collection in transform runs (#69047) 2026-02-03 23:38:23 -05:00
dpsutton
604a1d4301 log attribution (#68906)
* log attribution

```
2026-01-30 16:00:53,351 INFO audit-app.audit :: Copying complete. {mb-team=UX West}
2026-01-30 16:00:53,451 INFO notification.seed :: Seeding default notifications {mb-team=Gadget}
2026-01-30 16:00:53,647 INFO notification.seed :: Seeded notifications: {:skip 6} {mb-team=Gadget}
2026-01-30 16:00:53,658 INFO startup.core :: Running setup logic SearchIndexInit ☑️ {mb-team=DevEx}
2026-01-30 16:00:53,658 INFO startup.core :: Running setup logic analytics-dev-mode-setup ☑️ {mb-team=DevEx}
2026-01-30 16:00:53,668 INFO jdbcjobstore.JobStoreTX :: ClusterManager: detected 1 failed or restarted instances.
2026-01-30 16:00:53,668 INFO jdbcjobstore.JobStoreTX :: ClusterManager: Scanning for instance "mbp-m1.lan1769787254192"'s failed in-progress jobs.
2026-01-30 16:00:53,671 INFO search.core :: Initializing search indexes {mb-team=UX West}
2026-01-30 16:00:53,671 INFO core.QuartzScheduler :: Scheduler MetabaseScheduler_$_mbp-m1.lan1769788852529 started.
2026-01-30 16:00:53,671 INFO task.impl :: Task scheduler started {mb-team=UX West}
2026-01-30 16:00:53,678 INFO util.queue :: Starting listener field-value-invalidate with 1 threads 🎧 {mb-team=DevEx}
2026-01-30 16:00:53,688 INFO util.queue :: Starting listener search-index-update with 1 threads 🎧 {mb-team=DevEx}
2026-01-30 16:00:53,688 INFO core.core :: Metabase Initialization COMPLETE {mb-team=UX West}
2026-01-30 16:00:53,697 INFO core.core :: Metabase Initialization COMPLETE in 3.2 s (JVM uptime: 53.0 s) {mb-team=UX West}
2026-01-30 16:00:53,735 INFO search.core :: Found existing search index, and using it. {mb-team=UX West}
```

* include env variable

```shell
MB_LOG_TEAM_ATTRIBUTION=true clj -J-Xmx6g ...
...
2026-02-02 14:51:26,653 INFO core.core :: Setting up prometheus metrics {mb-team=UX West}
2026-02-02 14:51:26,655 INFO analytics.prometheus :: Starting prometheus metrics collector {mb-team=UX West}
2026-02-02 14:51:26,695 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191 {mb-team=UX West}
...
```

* copy module config file over for log attribution

* comment indentation

* restore module config location

* proper "from jar" detection

* correct logic for which env has a file and which a resource

* missed one

* ns cleanup

* trigger CI

* don't check config each time, only once
2026-02-03 17:25:51 -06:00
dpsutton
339136f500 fix kerberos tests (#69028)
* fix kerberos tests

in CI we're running:

```
[2/3] RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig

...

3.579 Hit:1 http://deb.debian.org/debian trixie InRelease
(#6 3.579 Hit:2 http://deb.debian.org/debian trixie-updates InRelease
(#6 3.588 Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
(#6 3.651 Hit:4 https://deb.nodesource.com/node_22.x nodistro InRelease
(#6 3.661 Reading package lists...
(#6 4.185 Reading package lists...
(#6 4.691 Building dependency tree...
(#6 4.834 Reading state information...
Dockerfile:5

--------------------

   4 |

   5 | >>> RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash ) \

   6 | >>>   && export DEBIAN_FRONTEND=noninteractive \

   7 | >>>   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig

   8 |

--------------------

failed to solve: process "/bin/sh -c ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig" did not complete successfully: exit code: 100

(#6 4.850 E: Unable to locate package yarn
(#6 ERROR: process "/bin/sh -c ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig" did not complete successfully: exit code: 100
------
 > [2/3] RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig:
3.517 2026-02-03 18:01:51 - To install N|solid Runtime, run: apt install nsolid -y
3.517
3.579 Hit:1 http://deb.debian.org/debian trixie InRelease
3.579 Hit:2 http://deb.debian.org/debian trixie-updates InRelease
3.588 Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
3.651 Hit:4 https://deb.nodesource.com/node_22.x nodistro InRelease

4.850 E: Unable to locate package yarn

```

and it seems like debian doesn't host yarn (anymore?) which is
understandable. So we just do:

```
&& npm install --global yarn
```

And we should be good.

LLM diagnosed this. The setup here is a bit strange to me but it cats
it's resulting dockerfile:

```yaml
      - name: Print compose config
        run: cat mba-compose.yml
```

which was helpful. That dockerfile references:

```yaml
  metabase:
    build:
      context: /home/runner/work/metabase/metabase/.devcontainer/
      dockerfile: Dockerfile
```

And it's that devcontainer we are fixing here

* trigger kerberos tests

it needs files to be changed:

```yaml
  run-presto-kerberos-test:
    needs: files-changed
    if: needs.files-changed.outputs.backend_presto_kerberos == 'true'
```

which is configured in `.github/file-paths.yaml`

```yaml
backend_presto_kerberos:
  - "**/presto_jdbc/**"
  - "**/presto_jdbc.clj"
  - ".github/workflows/presto-kerberos-integration-test.yml"
```

so i add a `^:synchronized` teset to a file that should trigger this
files changed check and we get CI

* fix how we detect presto changes

usually hyphens are underscores, so it was looking for
`"**/presto_jdbc/**"` but the driver module is not a classpath root and
it uses a hyphen. Also it excluded the test file. so just manually add
that in, although it would be hit by the hyphen rule that i added

* correct typo in test filename

* touch test file
2026-02-03 17:10:28 -06:00
appleby
222b6b1bd0 OSS sqlgen snowplow test cleanups (#68929)
* Update oss sqlgen snowplow tests to use snowplow-test/with-fake-snowplow-collector

To follow existing snowplow test patterns from other modules.

* Move chat-completion-returns-usage-test next to other chat-completion tests

* Rename estimate-sanity-test to estimate-simplified-models-test

And use "raw" model names by default

* Update model-pricing with all models returned by list-models

Also add a comment with code for updating the model-pricing table.

* Ensure estimated_costs_usd is both number? and pos?

to ensure you still get a readable diff when the predicate fails rather than a hard to debug stacktrace.

* Use mt/with-random-premium-token! to get valid test token
2026-02-03 15:06:59 -08:00
Jeff Bruemmer
52579e4906 docs - revise Enterprise edition installation recommendations (#69029) 2026-02-03 16:33:33 -05:00
Nathan Voxland
6e4d96a68f Search Indexing: Cache card schema upgrades (#68912) 2026-02-03 15:09:37 -06:00
Cam Saul
d39acdcb96 Add custom Kondo linter to enforce idiomatic var names for def and friends (#68969)
Kondo linter for def using correct casing
2026-02-03 20:50:33 +00:00
Filipe Silva
5166c30ea5 Trial ups (#68478)
* feat: send current user email on cloud reqs

* feat: upgrade modal

* refactor: simplify upsell banner integration & tests

* test: metabase-enterprise.cloud-proxy.api-test

* fix: error stats for upgrade modal

* etc: whitespace

* fix: upgrade modal should only show up for upgrade url

* feat: refresh page after upsell flow for module reload

* refactor: use global modals instead of localized jsx

* refactor: remove unnecessary mock data and convert to localized strings

* test: add hm.client interceptor tests

* constants to types

---------

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-02-03 12:17:30 -08:00
Nick Fitzpatrick
1858472ebe don't render data studio button for non admins or analysts (#68920) 2026-02-03 14:48:37 -04:00
github-actions[bot]
4120da5c4e Fix: Bookmark list is not updated when you archive a collection containing a bookmarked item (#67148)
* Fix: Bookmark list is not updated when you archive a collection containing a bookmarked item

Fixes #44499

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* remove unneeded e2e test

---------

Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2026-02-03 18:42:31 +00:00
Brad Anderson
091f66fc32 Fix #66446 - Disambiguate errors when moving content to remote synced collections (#68874) 2026-02-03 12:47:33 -05:00
Vamsi Peri
dbe8b1f36d Workspaces for editing Transforms (#66015)
Co-authored-by: Chris Truter <chris@metabase.com>
Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
Co-authored-by: Uladzimir Havenchyk <uladzimir@metabase.com>
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Co-authored-by: Stas Gavrylov <stasgavrylov@gmail.com>
Co-authored-by: Oleksandr Solovyov <alexander@solovyov.net>
2026-02-03 17:45:55 +00:00
Dan Stone
21c5c9c424 Add :transform-rolling stats to allow for up-to-date metering (#68999) 2026-02-03 17:16:16 +00:00
Noah Moss
3192d01612 Misc agent API improvements + llms-agent-api.txt (#68914)
* Misc agent API improvements + llms-agent-api.txt

* add llms-agent-api.txt

* Add more specific query execution response schema, fix some tests, and update llms.txt again

* Simplify count aggregation schema

* address comments, some other tweaks

* rename & move agent API llms.txt

* bump ci

* bump ci

* small change: ensure we record query execution properly with :agent context

* fix test
2026-02-03 12:16:00 -05:00
Maksym Yakubych
c3715127e2 fix: stacked bar chart crashes when card has multiple same-type aggregations (#68903) 2026-02-03 17:10:16 +00:00
Eric Normand
c32e0af3ee Bigquery and snowflake failing test QUE-3013 (#68916)
BigQuery can't do case statements with different types in each branch. Other dbs can. This fixes a test that ran a case statement with different types to skip BigQuery, but it adds a new assertion to check correct behavior without it.

This also corrects a fault in the SnowFlake driver that incorrectly assumed that convertTimezone() returned a timestamp_ntz but it returns a timestamp_tz. This wraps it in a cast back to timestamp_ntz.
2026-02-03 16:37:10 +00:00
Timothy S. Dean
59fd52ac43 Add dataset option to disable fk validation on batch insert (#68646)
Gives datasets a new option to specify that when being created fk validation should be disabled on insert
2026-02-03 09:36:50 -07:00
Mahatthana (Kelvin) Nomsawadi
2e9aa4019c Add support for auto refresh prop in modular embeddings (#68896)
* Add `autoRefreshInterval` to the SDK (#68729)

* Fix new callback don't get registered with our own `useInterval`

* wip

* Handle negative number

* Add autoRefreshInterval to StaticDashboard storybook

* Add autoRefreshInvertal to EditableDashboard storybook

* Add tests

* Make test order more sensible

* Add more test coverage

* Update types

* Update test format for consistency

* Make the condition clearer

* Fix wrong user-facing comment

* Fix wrong test name

* use the same jest fake timer configuration for all tests

* Address review

* Add support for `auto-refresh-interval` in modular embedding (#68830)

* Support `auto-refresh-interval` in modular embedding

* Make the test names more sensible

* Add tests

* Add an auto-refresh indicator (#68847)

* Add a dummy refresh indicator

* Add the actual icon

* Pass tests

* Add tests

* Fix another test
2026-02-03 16:30:35 +00:00
Stas Gavrylov
8db69364e8 Chore: Migrate pulse code to TS (#68908)
* Migrate DashboardSubscriptionsSidebar to TS. Related refactoring.

* Migrate redux pulse to TS

* Some more pulse-related migrations to TS

* Remove usage of Pulse and PulseParameter types. Replace with DashboardSubscription

* Fix prettier

* Remove type-casting

* GDGT-1649: Cleanup

* GDGT-1649: Fix TS error

* GDGT-1649: Fix unit tests

* GDGT-1649: Fix PR comments

* GDGT-1649: Fix PR comments

* GDGT-1649: Refactor setStates to remove side-effects
2026-02-03 18:01:12 +02:00
Eric Normand
62402df8b6 Create mutation testing skill (#68978)
A Claude skill with accompanying code for automating the mutation testing of a namespace.
2026-02-03 09:00:40 -07:00
Nathan Voxland
3ef22bbaec Better error handling in queue listeners (#68924)
Better error catching in queue listeners, with auto-restart
2026-02-03 09:34:39 -06:00
Nathan Voxland
00479dbf33 Fix reindex connection management (#68973)
Move reindex connection management to use a connection only around the writes, not try to use a connection across all writes, which may commit and therefore close server-side cursors still being used to read the next batch.
2026-02-03 09:27:09 -06:00
Maksym Yakubych
bbddb39150 fix: cannot save dashboard when dashboard was reverted to one with deleted filter (#68871) 2026-02-03 14:38:42 +00:00
Maksym Yakubych
49fbb0d24e fix: gauge chart breaks when sent via email/slack (#68730) 2026-02-03 14:33:53 +00:00
Jeff Bruemmer
3c5fbff8a8 docs - remote sync edits (#68923) 2026-02-03 14:29:16 +00:00
github-automation-metabase
9ce2f7da36 Auto-update documentation for master (#68984)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-03 09:25:45 -05:00
kevinkelleher12
f4e81f2c62 Allow non-admins to see timezone on Runs page tooltip (#68974) 2026-02-03 13:10:15 +00:00
kevinkelleher12
ac2083205b Fix empty tooltips (#68925) 2026-02-03 07:04:49 -05:00
Stas Gavrylov
f23b210cf1 E2E: Fix frontend port check. Adjust setting visibility (#68964) 2026-02-03 13:20:51 +02:00
Nemanja Glumac
a2f819bd08 Fix broken eslint tests (#68994) 2026-02-03 12:10:48 +01:00
Fraser
d818c6dd46 Remove dead code from admin settings redux (#68976) 2026-02-03 22:53:54 +13:00
Romeo Van Snick
e909583de0 Fix flake in native test (#68972)
* Add metaKey to test helpers

* Fix flake by using realPress helper
2026-02-03 18:24:13 +11:00
Nick Fitzpatrick
7abfb8753f Updating text color for filter counter chip (#68958)
updating text color
2026-02-02 16:51:41 -04:00
metamben
47304d3144 Add table-publish and table-unpublish events to the Activity log (#68899)
Add table-publish and table-unpublish events to the Activity Log

Closes QUE-2881

Register table-publish and table-unpublish as audit log events.
2026-02-02 13:14:55 -07:00
Eric Normand
5caa28c48a Add tests for lib.card/merge-model-metadata (#68869)
* Add tests for lib.card/merge-model-metadata

No mutants survived!

* kick ci
2026-02-02 19:22:56 +00:00
Eric Normand
636c376712 Test card->underlying-query (#68875)
Kills 100% of mutants
2026-02-02 18:30:51 +00:00
Eric Normand
d51ce7c743 Test model-preserved-keys (#68876)
100% mutants killed
2026-02-02 18:02:53 +00:00
Eric Normand
40c0273582 Add test for lib.card/fallback-display-name (#68865) 2026-02-02 17:16:14 +00:00
Eric Normand
b5c0fdd4e3 Fully test source-model-card (#68872)
* Add tests for source-model-card

source-model-card is only called from one function, card-returned-columns.
So we have to test source-model-card (which is private) through card-returned-columns.

This kills all mutants but 3, which have to do with the self-reference check in source-model-card. Is it really
necessary? It is an impossible branch to reach.
2026-02-02 10:56:16 -06:00
Eric Normand
1296b4671b Test lib.card/saved-question-metadata (#68868)
* Test lib.card/saved-question-metadata

* kick ci
2026-02-02 10:52:42 -06:00
Alexander Polyankin
b9ba7de970 Convert Transform Runs page to TreeTable and add a sidebar (#68892) 2026-02-02 16:26:54 +00:00
Ryan Laurie
0fa535476d Add Growth Engineering to Teams (#68959)
add growth engineering to teams
2026-02-02 07:59:57 -07:00
github-automation-metabase
b0d28fcfa4 Auto-update documentation for master (#68941)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-02 09:10:33 -05:00
Nemanja Glumac
6b1ceaf93b Update the latest docker tag when the latest major version matches (#68946) 2026-02-02 14:51:46 +01:00
Ngoc Khuat
db7f048d82 Snowflake: fix flaky test (#68844) 2026-02-02 12:12:04 +00:00
Fraser
4842e16f7c Upgrade to eslint v9 (#68772) 2026-02-02 22:39:13 +13:00
Nemanja Glumac
cd1be87231 Upgrade Chrome setup action to version 2 (#68915) 2026-02-02 21:21:45 +13:00
Fraser
89a8970e4a Fix no unused expression violations (#68939) 2026-02-02 13:21:07 +13:00
Fraser
2e7aafe3a0 Fix rules of hooks violations (#68940) 2026-02-02 13:20:42 +13:00
metabase-bot[bot]
39310d4798 [chore] Update E2E test timings with recent data (#68936) 2026-02-02 09:10:32 +13:00
Ryan Laurie
23be6baa0e Entity Picker v26 (#66978)
* new pickers

implement all pickers

remove test code

remove dead code

type fixes

reorganize

type fixes

data picker plus plus

more fixes

type fixes

fix column test ids

type and testfixes

some e2e test updates and kick off ci again

improved default states

more e2e test updates

test updates

better loading state

lint fixes

better root namespace handling

fix more root collection nonsense

improve backparsing logic

fix closing multiple modals on esc or enter

more e2e test updates

e2e test updates 4

fix (some) backparsing and add tests

fix spacing

e2e test updates 5

more backparse fixes

weird snippet deal

more tenant shenanigans

sweet sweet unit tests

add back NewDashboardDialog

more e2e tests and start NewDashboardDialog unit test

lint fixes

fix infinite render loop 😅

various fixes

bug fixes

search improvements

better cache hitting

dialog unit tests

test fixes

mucho test fixes

* fix conflict resolution errors

* test and type fixes

* bug and test fixes

* New folder button for snippets and transforms, e2e tests

* fix some dashboard cases

* test fixes

* entity picker e2e tests

* much fixo

* more e2e fixes

* fix some flakes

* prettier

* fixes

* more e2e test updates

* fix sdk component tests

* some stabilization

* fix dashboard saving bug

* prettier

* address review comments

* test fixes

* fix sandbox tests

* obey the linter

* cant pass null namespace

* oh types

* timeline

* fix default expanded 😫

---------

Co-authored-by: Kevin Kelleher <kevin.kelleher@metabase.com>
2026-01-31 02:57:52 +00:00
Nemanja Glumac
7ed4b012e5 Document rootless docker limitations (#68913) 2026-01-30 23:47:33 +01:00
Tyler Plude
e38d87f616 Metabot OSS Single Shot Text-2-Sql (#67883)
* Experiment with communicating with LLMs in Clojure

* Libor comments

* switch to new openai /v1/responses api, check for structured output support

* support for claude to show how different adapters are

* linter fixes

* update llm config edn

* init chat completion endpoint and env vars

* basic sqlgen BE endpoint

* BE test script

* basic table schema context extraction

* temp hack EE inline entrypoint to use OSS sql gen

* BE OSS async & streaming support

* BE OSS async & streaming support

* structured json response

* dialect instructions and sys prompt mustache

* hacky disable file logging via env var

* improved dialect mapping

* improved table metadata

* fix merge conflict

* abstract out sql generation to a seperate hook

* move MetabotPromptInput and MetabotInlineSQLPrompt components into OSS land

* always register metabot context rather than doing it conditionally in enterprise

* move OSS implementation into a seperate file

* oss implementation first pass

* add setting to know if the feature is enabled or not, optionally show ui based on if it is enabled, consolidate state into a single hook call to fix OSS issues, gets everything working

* clean up

* add test coverage

* revert metabot context changes, they did not end up being needed

* restrict @mentions to tables in OSS and models, tables, questions in EE

* send current sql value and no longer send buffer id

* add anthropic provider

* dumb module resolution workaround to get unit tests working correctly

* if there is only one search model provided preselect it

* tweak sys prompt; add table descriptions

* improved table & field metadata

* tweak model env var

* add openai settings

* fix CSP tiptap nonce console error

* fix oss not having access to default import of use-metabot-sql-suggestion hook in prod builds

* add backend support for source_sql

* OSS SQL Generation v1.6 (#68584)

* update layout

* impl table input bar

* persist state on open / close of inline sql prompt input

* ui improvements, referenced_entities now in req/res body

* support referenced_entities param in /generate-sql; add extract-tables endpoint

* use search, fix some ux/ui issue with dropdown

* fix sizing issue

* simplify generate-sql response format; properly union the referenced entities

* return table model spec in response

* updated backend tests

* improve table selection logic using new endpoint changes w/ richer data

* rate limiting; throttling; http timeouts; max resp tokens

---------

Co-authored-by: Sloan Sparger <sloansparger@gmail.com>

* small spacing / sizing corrections

* fix ee extracting tables when it should not, add test cases

* handle disabeld state and enter press better

* cleanup

* fix modules

* add init; fix kondo

* test fix

* fix modules

* Add snowplow events to oss sqlgen endpoints (#68822)

* Copy token_usage snowplow schema from ai-service

* Add :snowplow/token_usage to metabase.analytics.snowplow/schema->version

* Add basic anthropic cost estimation based on static tables

* Return :usage and :duration-ms from llm.anthropic/chat-completion

* Add snowplow token_usage tracking to oss /generate-sql endpoint

* Add snowplow token_usage tracking to oss /generate-sql-streaming endpoint

* Add snowplow simple_event tracking for sqlgen success and failure events

* Consolidate snowplow tracking tests

* Appease whitespace linter

* Don't use non-api analytics.setting namespace

* Ensure duration_ms is an integer in snowplow events

* Add note about oss instances to hashed_metabase_license_token schema description

Co-authored-by: Thomas Schmidt <thomas@metabase.com>

* Fix snowplow lint by adding old versions of token_usage schemas

The snowplow linter was complaining that these older schemas were missing. These versions had been deleted from the
ai-service repo, so weren't copied over. Restore them from the last version in ai-service prior to being deleted.

---------

Co-authored-by: Thomas Schmidt <thomas@metabase.com>

* Add README reminder to token_usage snowplow schema

See also https://github.com/metabase/ai-service/pull/605

* cleanup streaming

* rm stream test

* pr feedback & test fixes

* test fix

* [Metabot] OSS SQL generation admin UI changes (#68824)

* wip

* load models async, move model input to a select, show error if deprecated model

* move to password input for api key

* handle case where env vars have been set via env vars and can not be changed

* clean up oss view

* remove token checks for deciding to upsell metabot

* be tests for new models endpoint

* fix bug

* fix broken api tests

* ui feedback, token validation, style fixes

* unit tests

* fix cypress

* fix e2e test tag

* type fixes

* condo / eastwood fixes

* fix unit tests

* fix e2e test

* fix stale css var reference

* pr feedback

* fix var

* fix n+1 query; improve metadata fetching

* driver multimethod for dialect instruction resource; review PR cleanups & fixes

* pr feedback

* fix added in driver multimethod

* whitespace lint

* address my own comments

---------

Co-authored-by: Oleksandr Solovyov <o@solovyov.net>
Co-authored-by: Sloan Sparger <sloansparger@gmail.com>
Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
Co-authored-by: Thomas Schmidt <thomas@metabase.com>
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
Co-authored-by: Noah Moss <noahbmoss@gmail.com>
2026-01-30 14:40:48 -08:00
Rodrigo López Dato
f6e9a91db7 Show Cloud region IDs next to names (#68918) 2026-01-30 18:49:02 -03:00
Uladzimir Havenchyk
423aafea99 replace moment with dayjs in cljs (#66914)
* replace moment with dayjs in cljs

* Fix CLJS compilation with DayJS port of metabase.util.time

* fix some tests

* fix time parsing in drill chart

* formatting

* make a better fix

* kondo

* fix sdk test

* indent

* drop moment from locales

* reorder imports

* ran bin/mage cljfmt-all to indent

* Add an ignore for 1 unsorted namespace

- cljfmt makes the namespaces unordered -> kondo complains

* typo

* attampt to move logic to clojurescript

* one more thing to remove business logic from metabase-lib

* address cljs review

---------

Co-authored-by: Braden Shepherdson <braden@metabase.com>
Co-authored-by: Bryan Maass <bryan.maass@gmail.com>
2026-01-30 23:38:35 +03:00
Riley Thompson
78ae095422 Athena and Databricks adjustments for data upload (#68821)
* fix upload

* use shared impl
2026-01-30 20:18:11 +00:00
bryan
297d612165 Simplify CI workflow trigger conditions (#68917)
Reverts 730265b198
2026-01-30 21:01:50 +01:00
Edward Paget
8ae78915ed feat: add library/transforms toggles to modal (#68852)
* feat: add library/transforms toggles to modal

In the 'Set up git sync' modal in data studio this adds pre-selected
toggles to sync the library and transforms. This also creates the
library if you select it to sync, but it has not yet been created.

* fixup! push the library/transforms behavior into CollectionList

* fixup! better types to reduce casting

* fixup! missing mock setup

* Update enterprise/frontend/src/metabase-enterprise/remote_sync/components/RemoteSyncAdminSettings/RemoteSyncSettingsForm.tsx

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>

* fixup! separate library sync component

* fixup! prettier

---------

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
2026-01-30 19:31:09 +00:00
Nick Fitzpatrick
02b0bbaf76 updating frontend dev guid colors section (#68904) 2026-01-30 15:26:31 -04:00
Alexander Polyankin
2062c3fb13 Fix colors and strings in the deps sidebar (#68901)
Fix colors and ttag
2026-01-30 19:15:18 +00:00
Eric Normand
37c991c292 Mutation testing basics (#68857)
Initial commit of mutation testing library.
2026-01-30 10:52:47 -06:00
Riley Thompson
3142c39435 Run transforms with a temp table + rename to avoid blocking queries (#68756)
* add fix and test

* dont drop bigquery tables and add test

* use atomic renames when possible

* use helper functions

* use existing wait-for-table

* use shared temp-table-name

* small change

* remove bigquery hack, make more similar to python impl

* address comments

* use random suffix and table name for temp tables

* use table hash

* update temp-table-name

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* mocked test to verify strategy selection

* fix test

* test description

* remove test

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 11:39:26 -05:00
Edward Paget
898b7b4c38 feat: apply remote sync settings to snippets (#68902)
Adds new spec-driven methods to detect writability of remote-sync
controlled methods. These use the existing sync-eligibility settings so
in the future we can straightforwardly apply these settings to
remote-sync controlled models (TODO: follow up to build them for the
other models).

Adds batched-versions of these checks to avoid n+1 queries when loading
can_write for models.

Adds tests of remote-sync checks for snippets.
2026-01-30 10:33:47 -06:00
Maksym Yakubych
c5ff6bbbbd fix: documents charts rendering when resizing is sluggish (#68204) 2026-01-30 15:31:04 +00:00
Noah Moss
50dac4248d Split out more granular error codes for metabot tools (#68627)
* Split out more granular 400 vs 404 error codes for metabot tools

* a couple new tests

* fix test

* fix tests, cleanup

* discrete error handling in resolve-datasource

* refactor

* undo some refactor to fix tests
2026-01-30 10:04:53 -05:00
Timofey Kachalov
df8fd2aa98 Add content translations for aggregations (#68733) 2026-01-30 17:58:24 +04:00
Oleksandr Solovyov
e597be0c10 make bin/mage run-tests able to run a single test (#67450) 2026-01-30 12:35:11 +00:00
Mahatthana (Kelvin) Nomsawadi
64fb9ea259 feat(sdk, embed-js): Add an alerts support to modular embeddings (#68777)
* Add an alerts button on the SDK (#67796)

* Prepare to add alerts to SDK

* Remove unrelated prop from storybook

* Add basic alerts button

* Only show alerts button with the proper flag

* Prevent download button from being shown without proper flag

* use CSS to hide things instead of JS

* Properly position all question buttons

* Use JS to hide empty divs as pure CSS is impossible

* Render alert modal ✌️

* Fix type

* Add todo

* Structure the components better

* Control alert modal state

* Add interactive question storybook

* Make interactive and static question button styles consistent

* Add alerts modal to interactive question

* Make alert button works with custom layouts

* Fix tests

* Fix unit tests

* Fix import order issue

* Remove outdated comment

* Add the same condition to display alert button from the core app

* Polish

* Modify question storybooks to show a question instead of a model

* Hide empty elements more reliably

* Add more conditions to display alert button

* Remove unused `classNames` prop

* Use the same style as the interactive question one

* Remove outdated diff

* Fix alerts button not working in custom layouts

* Remove another unused code

* Add a basic test

* Add unit tests

* fix visibility logic

* Fix E2E tests

* Make assertion on static question tests better

* Improve assertions

* Add interactive question unit tests

* Add e2e test for static question

* Add interactive question e2e tests

* Fix subcomponent

* clarify comment

* Hide other channels than email on the alert modal (#68184)

* Hide channel options on alerts modal

* Add unit tests

* Make the test name clearer

* Fix can't view created notifications the first time (#68197)

* Fix can't view created notifications

* Add tests

* Remove unnecessary return type

* Add a safety guard

* Hide Alert (and download) button on edit mode (#68189)

Hide some buttons on edit mode as it makes no sense there

* Alerts polishing (#68477)

* Misc. improvements

* Make it typesafe

* Add alerts to modular embedding (#68286)

* Add the option in modular embedding wizard

* Support `withAlerts` in modular embedding

* Close the modal after hiding the alert button

* Add E2E tests

* Fix type

* Fix `withAlerts` not working on modular embedding with `drills: false`

* It's 2026!

* 1 plugin to rule 'em all!

* Fix E2E after merging master

* Fix test name

* Add alerts analytics (#68531)

* Add alert setup analytics

* Track withAlerts on modular embedding

* Update snowplow schema

* Fix E2E tests

* Fix schema version

* Remove links from alerts test email (#68547)

* Remove links from alerts template

* Remove links from alert email computed part

* Add tests

* Make embedding util easier to use

* Make alerts and subscriptions payload lighter

* Remove unexpected pprint

* Remove links from alert email via tasks (#68610)

* Save notification card's disable_links when creating

* Add tests
2026-01-30 11:32:31 +00:00
William
52f689cb36 Fix cloud implicit join tests (#68762)
A previous pr broke some tests on master, and this fixes them.
2026-01-30 10:19:47 +00:00
Romeo Van Snick
c51ca23c95 Use getter function to move element (#68714) 2026-01-30 15:10:26 +11:00
Alexander Polyankin
0bacd6c5ca Dependency diagnostics sidebar updates (#68825) 2026-01-30 03:52:21 +00:00
Phoomparin Mano
f46fdd8d27 fix(sdk): fix failing tests for white-labeled colors (#68790) 2026-01-30 09:55:49 +07:00
Fraser
27fd3aac36 Delete fuzzing workflow (#68880) 2026-01-30 15:13:58 +13:00
bryan
92a60c8529 CI: query-processor module should trigger driver tests (#68877) 2026-01-30 01:14:36 +00:00
Anderson
ee030befe2 Fix empty Python Library not showing placeholder/comment (#68826) 2026-01-29 22:11:38 -03:00
Nick Fitzpatrick
5f956d51bd Remove brand-light and brand-lighter (#68290)
* brand key adjustments

* loki tests

* handle the forgotten brand-dark

* Update Loki Snapshots

* removing brand-hover from dynamic-css-vars

* Adjustments to calendar picker colors

* small adjustments on the permissions pages

* sdk: remove background-hover tests from sdk as dynamic css derives are replaced with color-mix

* stupid spelling

* building shared resources

* Adjusting unit test, loki images

* rebasing adjustments

* Update Loki Snapshots

* small color fixes while I wait for loki

* re-adding highlighted class

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
2026-01-29 20:06:28 -04:00
John Swanson
590c8945fc Analysts can do crud on segments and measures (#68501)
* Data Analyst CRUD on measures/segments

Data analysts with unrestricted view-data permissions on a table can now
create, update, and delete segments and measures for that table
(previously superuser-only).

`can-read?` was already granted by the `manage-table-metadata` permission.

Add permission tests for `can-write?` and `can-create?` methods.
2026-01-29 23:53:21 +00:00
metamben
c056b03d89 Deps breaking broken (#68866)
* Add rename /broken to /breaking and add new /broken

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-01-30 02:47:55 +03:00
Maksym Yakubych
b4cf7383a4 fix: y axis not shown even if it would fit (#68861) 2026-01-29 15:09:10 -08:00
Edward Paget
9c003314be feat: enable transform setting on first import (#68807)
* feat: enable transform setting on first import

When a we import a remote that has transforms set the
`remote-sync-transforms` setting to true.

Update the remote sync object table clean up to be driven by the spec
configuration.

Add tests showing that transforms are consistently synced and erased
according to the following rules:

1. if the instance has `remote-sync-transforms` off and local transforms
and the remote does not have transforms content they are preserved after
an import
2. if the instance has `remote-sync-transforms` off and local transforms
and the remote has transforms content, the local transforms are
completely replaced by the remote.
3. if the instance has `remote-sync-transforms` on and the remote has
transforms content any local transforms are completely replaced by the
remote.
4. if the instance has `remote-sync-transforms` on has local transforms,
but the remote has no transforms, the local transforms are removed on import.

* fixup! relocate settings update

* fixup! don't let python libraries clash on import

* fixup! transactions for mysql
2026-01-29 22:16:41 +00:00
kevinkelleher12
06a24797b4 Remove Security and Appearance from embedding settings related links on OSS (#68151) 2026-01-29 20:53:58 +00:00
Edward Paget
ad8af02598 feat: transform setting into collection list (#68758)
* feat: transform setting into collection list

Move the setting for syncing transforms into the list of collections
available to remote sync, so conceptually the transforms root collection
looks like a standard syncable collection.

* Clean up FE a little bit

* undo unneeded changes

---------

Co-authored-by: Anderson <anderson@metabase.com>
2026-01-29 14:47:55 -06:00
Riley Thompson
798fc4aff6 Custom test on connection checkout for clickhouse (#68808)
* work around clickhouse bug

* driver change log

* use c3p0 test

* Add todo comment

* kondo

* more kondo
2026-01-29 20:32:51 +00:00
Nick Fitzpatrick
eb0a8d4900 Uxw 2736 improve transitions between main app data studio and admin (#68508)
* temp

* hook up mode switcher in other apps

* Ci issues

* adding get help, fixing e2e tests, other adjustments

* most unit tests

* rename to profile link?

* adjusting unit tests with routing

* partial feedback

* rename profile link

* base current app off routes array

* adjustments

* add non-admin user state, fix unit tests

* PR feedback

* fixing test

* fixing e2e

* only 1 app switcher in admin navbar

* e2e adjustments
2026-01-29 16:08:26 -04:00
Nathan Voxland
d1e940e66b Don't cascade delete transform runs on transform delete (#68642) 2026-01-29 13:16:28 -06:00
Jeff Bruemmer
781282dd40 docs - embedding edits (#68567)
* embedding edits

* edits

* Apply suggestion from @jeff-bruemmer

* edits

* Apply suggestion from @jeff-bruemmer

* update

* sso

* edits
2026-01-29 18:55:43 +00:00
bryan
730265b198 fix: re-run CI when break-quarantine-* or ci:all-cloud-drivers labels are changed (#68037) 2026-01-29 18:29:15 +00:00
Brad Anderson
0897ae0847 Fix Dependency Graph icon (#68855) 2026-01-29 12:57:07 -05:00
Timofey Kachalov
7b921d8f43 Deprecate isEEBuild helper (#68848)
Co-authored-by: Nicolò Pretto <info@npretto.com>
2026-01-29 21:34:11 +04:00
Stas Gavrylov
e22e0e5fb1 GDGT-1581: Add Python preview disclaimer (#68789)
* GDGT-1581: Update layout for Python preview message

* GDGT-1581: Add e2e test

* GDGT-1581: Rename 'Results' tab to 'Results preview'

* GDGT-1581: Adjust footer layout

* GDGT-1581: Add dismiss button to allow closing the footer

* GDGT-1581: Replace CSS with inline props

* GDGT-1581: Fix e2e test
2026-01-29 18:46:36 +02:00
Brad Anderson
c9bcbbfd73 UXW-2862 Fix test flake (#68784) 2026-01-29 11:41:36 -05:00
Brad Anderson
172e56f4b7 Fix data studio guard (#68781) 2026-01-29 11:16:02 -05:00
Eric Normand
1e3406219c Improved message for job failure due to routing (#68804) 2026-01-29 09:27:22 -06:00
Eric Normand
ad8376f6cc Don't double-convert expressions with convertTimezone() (#68740)
In the case statement, the default case did not TIMEZONE() to alter the timezone. The cases with TIMEZONE() returned a timestamp. The default case without TIMEZONE() returned timestamptz. Postgres reconciled the different types by converting all of them to timestamptz. So the timestamp was altered (by TIMEZONE()), but a new UTC timestamp was added (by the cast).

When the post-processor formats the rows, it checks that the metadata for the column has :converted_timezone. If it has that, it is formatted in the converted timezone, and since it's UTC, it will convert it again, a second time, which is incorrect.

The fix here is to check if the returned column is a timestamptz and strip it before formatting. We assume the database has already done the conversion. This avoids the second conversion.
2026-01-29 09:04:30 -06:00
John Swanson
bf81141508 allow getting transforms in root collection (#68731)
allow getting transforms in root collection
2026-01-29 15:00:57 +00:00
Noah Moss
05c2aff020 Split agent api out as a separate friend module to metabot-v3 (#68814)
* Split agent api out as a separate module

* remove old files

* cleanup

* fix module config
2026-01-29 09:57:08 -05:00
Aleksandr Lesnenko
bd3f1d4632 Transforms permissions (#66296)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
2026-01-29 09:29:01 -05:00
Sébastien
9743b3cbee Added link to doc for full app embedding (#68773)
* added link to doc for full app embedding

* Apply suggestions from code review

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>

---------

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2026-01-29 15:01:05 +01:00
github-automation-metabase
50c809f3fa Auto-update documentation for master (#68820)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-29 08:27:11 -05:00
Timofey Kachalov
0559e0beee Hide Guest embedding status bar when guest embedding is disabled (#68836) 2026-01-29 16:06:34 +04:00
Dan Stone
cf347ce318 Throw db-routing error on anonymous transform call (#68788)
Fixes GDGT-1588
2026-01-29 11:29:25 +00:00
Stas Gavrylov
eea96b2477 GDGT-1356: Alert Notification Cron Syntax is misleading (#68834)
* GDGT-1356: Adjust day of week parsing in cron string

* GDGT-1356: Add unit test
2026-01-29 13:14:35 +02:00
da
390bcd144e Change log level from info to debug for ignored params on qp (#68748)
reducing a bit more the verbosity of our logs, this time on cards with old metadata
2026-01-29 05:47:36 -03:00
Jakub Chodorowicz
383f6ba968 gdgt-1377 deselect and hide from bulk view tables not matching selection (#68469) 2026-01-29 09:26:54 +01:00
Aleksandr Lesnenko
450f5cc9ba data studio upsell (#68527)
* data studio upsell

* refactor: fix route guards

* fix: lint comments

* fix: data studio layout tests

* fix: remove local stub for api

* fix: moar lint errors

* fix: comments

---------

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2026-01-28 19:57:24 -04:00
metamben
353260e583 Keep field-values for detail-only fields (#67540)
* Keep field-values for detail-only fields

Closes #10851

* Make sure old-preview-display is set

* Fix test
2026-01-29 02:49:33 +03:00
Maksym Yakubych
b300a6118f fix: search in mini data picker only shows loading on the first load (#68365) 2026-01-28 17:53:29 -05:00
Maz Ameli
86410d0667 Boat instead of bird (#67612)
* boat instead of bird

* update tests
2026-01-28 22:41:26 +00:00
Nemanja Glumac
5d84cc6c3f Add a note about the Metabase config (#68803) 2026-01-28 22:51:19 +01:00
Edward Paget
ef4136d69e fix: clean up style issues in new remote-sync code (#68753)
* fix: clean up style issues in new remote-sync code

Fixes a grab bag of small style/docstring issues I found after the
parent PRs were merged.

* fixup! lint

* fixup! keep the newsnippetpage as always dirty
2026-01-28 15:42:02 -06:00
John Swanson
16e013a90d flake: fix temporal pollution (#68745)
flake: frozen clock
2026-01-28 21:31:04 +00:00
bryan
595e171f34 ci: add H2 OSS driver tests to catch OSS-only failures (#68649) 2026-01-28 21:25:05 +00:00
John Swanson
f01589a9d6 Fix migration for data studio (#68585)
* Fix migration for data studio

We usually auto-populate some other fields in permissions based on the value of object - perm_value, perm_type, and collection_id.

This obviously doesn't happen in a migration! So set them manually here.

* just roll forward
2026-01-28 13:15:30 -08:00
John Swanson
bf6c8b3459 Fix throw-if-last-admin! (#68198)
[UXW-341: Reactive old admin account is not possible](https://linear.app/metabase/issue/UXW-341/reactive-old-admin-account-is-not-possible)

Co-authored-by: Ed Paget <edpaget@users.noreply.github.com>
2026-01-28 13:14:31 -08:00
metamben
65189a0b69 Push the analysis of the dependents to the job (#68749)
* Push the analysis of the dependents to the job

Fixes QUE-3001

The analysis findings of dependents are marked as stale (if they exists) and the analysis job picks them up with
higher priority. Also, the job is triggered right after the analysis of the dependency and doesn't stop until all
stale findings are refreshed.

* Fix boolean type in migration

* Set *warn-on-reflection* to true

* Stick to SQL change

* Fix tests

* Remove race condition

* Process review feedback

* fixes

* fix tests

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-01-28 20:52:58 +00:00
John Swanson
d950e70482 No special Synced Collection on remote sync setup (#68499)
* No special Synced Collection on remote sync setup

[UXW-2684: Remove creation of special "Synced Collection" that gets created when Remote Sync is setup](https://linear.app/metabase/issue/UXW-2684/remove-creation-of-special-synced-collection-that-gets-created-when)

Co-authored-by: edpaget<ed@metabase.com>

* fix e2e tests
2026-01-28 12:40:50 -08:00
John Swanson
54e150e856 flake: wait for card query after revert (#68796)
The revert operation triggers a chain: revert API -> reload card page.

Test was only waiting for the revert API, then sometimes it would manage
to click the History tab *before* the page reload. Then the page reloads
and we're not on the History tab anymore.

Waiting for the card query request to finish means that we've reloaded
the page and ready to roll.
2026-01-28 11:54:05 -08:00
Riley Thompson
5959ca6c82 ClickHouse to always support schemas (#68517)
* set schemas to true and add migration

* just enable schemas

* remove migration

* add test

* fix schema test
2026-01-28 14:03:56 -05:00
Noah Moss
6b330140ff Semantic layer agent API endpoints (#68260)
* New endpoint implementations

* add new schemas for new endpoints

* new field values endpoints

* simple search endpoint + bastic test

* WIP - query construction endpoint

* Query construction tests, convert :output errors to real 404

* Basic query execution endpoint that just wraps qp/process-query

* Add query response schema

* Add descriptions to malli specs

* Add more tests, simplify some schemas

* Misc fixes, malli description improvements, try to fix decoding/encoding stuff but will need to revisit

* fix whitespace

* Greatly simplify schema sharing w/existing tool endpoints

* cleanup ns

* Fix some tests

* Fix up metric field values test

* add agent-client test helper, and new agent-api-user-binding-test

* simplify base64 query encoding

* small cleanups

* Address feedback

* add comment

* bump ci

* bump ci

* fix modules

* switch to agent-api feature flag
2026-01-28 14:00:28 -05:00
Nathan Voxland
24b7d886aa Paginate caching dashboard (#68242) 2026-01-28 12:52:39 -06:00
kevinkelleher12
b27e93965d Make sunburst charts reflect colors set in the appearance tab (#68641) 2026-01-28 14:12:28 -04:00
Cam Saul
f563a91095 Add additional tables to Lib test metadata (#68754)
* Add additional tables to Lib test metadata

* Cljfmt

* Test fixes 🔧

* Tell generators how to generate booleans
2026-01-28 09:02:39 -08:00
Alexander Polyankin
b0cfcca1e5 Dependency diagnostics UI polish (#68761) 2026-01-28 16:52:26 +00:00
Maksym Yakubych
0421a12c9c fix: documents ignore base path when linking to dashboards (#68633) 2026-01-28 16:31:27 +00:00
Noah Moss
cb42387606 Ensure we catch semantic search errors with failover and prometheus metrics (#68639)
* Ensure we catch semantic search errors before RRF + add a new prometheus metric

* Revert "Ensure we catch semantic search errors before RRF + add a new prometheus metric"

This reverts commit d972fdf6df.

* Move fallback logic to semantic-search.core to not be metabot-specific, add test
2026-01-28 10:23:42 -05:00
Nick Fitzpatrick
731f564a04 Uxw 2696 handle charts where manual y axis hides all data (#68156)
* off grid detection

* woof

* fixing bad counts

* adjusting no data points check

* expose initalUiState in visualizer

* cleaning up dashcard functions

* adjust broken behavior for existing tests

* e2e tests

* PR feedback

* remove buttons to open settings and auto adjust. Adding tests for pinned cards and documents

* removing unneeded code, pr feedback, and adding loki screenshots

* fix silly thing
2026-01-28 15:13:59 +00:00
Timofey Kachalov
d41abaea80 Fix flaky content-translations.cy.spec.ts e2e (#68776) 2026-01-28 16:52:12 +04:00
Sébastien
13af38d9ca Fixed date range parameter widget can overflow in embed flows (#68724)
* fixed date param ovrflowing in embed

* added loki test
2026-01-28 11:59:31 +01:00
Romeo Van Snick
7d107764fe Fix flake in transform repro (#68759)
* Fix flake

* fix typo
2026-01-28 21:34:05 +11:00
Anderson
b871ae4909 Make segments read-only for published tables also on admin (#68651)
* Make segments read-only for published tables also on admin

* improve test coverage

* group tests
2026-01-28 03:25:53 +00:00
github-automation-metabase
114541e4fc Auto-update documentation for master (#68763)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-27 21:35:42 -05:00
bryan
0982712225 Enable fake-sync for Snowflake driver tests (#68322) 2026-01-27 15:47:40 -07:00
Edward Paget
965ce2a47b feat: add remote-sync support for PythonLibrary (#68515)
Add support for syncing PythonLibrary entities (Python transform libraries)
with a Git repository when remote-sync-transforms setting is enabled.

Implements serdes serialization for pythonlibraries using `path` as the
entity id.

Adds FE changes to refresh on dirty state and show changes in the AllChangesView
2026-01-27 16:09:31 -06:00
Noah Moss
7316888913 Semantic layer agent API groundwork + auth (#68163)
* Add support for versioned endpoints to deftool

* Create new API namespace + add custom jwt middleware

* add kondo module dependency

* revert the deftool stuff which isn't needed now

* fix lint issues

* fix jwt case insensitivity issue; more structured errors for auth issues

* small jwt cleanups

* Add support for session token exchange

* cleanup, lint, tests

* more test cases, cleanup

* bump ci

* Restructure session logic to use normal middleware, add test for session expiration

* fix up module config

* share more code with jwt sso module + remove some now-redundent tests

* try to fix tests by using existing SSO JWT test setup

* fix whitespace

* fix up module config
2026-01-27 16:49:55 -05:00
John Swanson
fe290f97e7 Fix collisions in test log file uploads (#68739)
1. if the `log-artifact-suffix` is empty, just do
`test-logs-{github-job}`.

2. include a `log-artifact-suffix` argument for the driver tests

This way we don't get 409 conflict errors when uploading logs on test
failures for driver tests.
2026-01-27 12:22:57 -08:00
Gabriel Moreno
794819ead2 Data Studio Owners, Alignment & Dependency diagnostics icon (#68707)
* refactor: remove avatars and "no owner" fallback from transforms list

* refactor: right-align rows column on data structure

* fix: search_check icon fill color
2026-01-27 16:20:55 -04:00
Riley Thompson
2ef8d50387 Fix redshift sync failing with duplicate key error (#68097)
* select distinct

* filter out duplicates

* skip duplicate cols entirely

* clean up test

* address comments
2026-01-27 19:34:40 +00:00
William
73766cf355 implicit joins get implicit fields added (#68394)
Say you are doing an implicit join from orders to products in order to summarize by products.category. Previously, with implicit joins, we join with the actual products table instead of a select blah from products wrapper, and so the various fields returned by the join were returned under their original name. However, the code would abbreviate excessively long column names from the joined table and break the query.

That difference was due to add-implicit-fields running before add-implicit-joins. Explicit joins got implicit fields added, while implicit joins didn't get those fields. This pr runs add-implicit-fields a second time after add-implicit-joins, which makes implicit and explicit joins compile to the same (correct) sql.
2026-01-27 13:01:52 -06:00
John Swanson
38f42a9386 Don't automatically pull when in read-write mode (#68500)
Don't automatically pull when in read-write mode

Co-authored-by: edpaget<ed@metabase.com>
2026-01-27 10:43:18 -08:00
Oleksandr Yakushev
0ec522227b [match-lite] Make match-lite recursive by default (#68658)
Make match-lite recursive by default
2026-01-27 20:27:01 +02:00
John Swanson
cb42b96ca8 flake: empty schemas in target schemas (#68742)
The test was missing an explicit database selection step which sometimes
resulted in the Save button being disabled.

Also removed the unnecessary sync_schema call — the syncable_schemas
endpoint queries Postgres directly via the driver, so no metadata
sync is needed.
2026-01-27 09:58:51 -08:00
Oleksandr Yakushev
52f48e2400 Refactor match-lite and introduce :or clause (#67345)
* Refactor match-lite

* Add support for :or syntax
2026-01-27 19:23:18 +02:00
John Swanson
36a5234efc Do not delete built-in transform tags on sync (#68727)
* Do not delete built-in transform tags on sync

I found that some tests were failing intermittently - sometimes
TransformTags were present, and sometimes they were missing. I tracked
it down to this test, which enables and then disables remote syncing
transforms.

The issue is that if we sync transforms (... and transform tags), then
unsync them, then we delete everything that was synced - including the
built-in tags.

We should exclude these from deletion.

* Fix serialization API tests
2026-01-27 08:29:58 -08:00
dpsutton
065c23b648 prometheus metrics for jvm startup (#68728)
logs:
```
2026-01-27 15:02:23,442 INFO util.queue :: Starting listener field-value-invalidate with 1 threads 🎧
2026-01-27 15:02:23,448 INFO util.queue :: Starting listener search-index-update with 1 threads 🎧
2026-01-27 15:02:23,448 INFO core.core :: Metabase Initialization COMPLETE
2026-01-27 15:02:23,453 INFO core.core :: Metabase Initialization COMPLETE in 4.8 s (JVM uptime: 57.8 s)
```

metrics:

```
❯ http get :9191/metrics | grep startup
metabase_startup_jvm_to_complete_millis 57764.0
metabase_startup_init_duration_millis 4816.0
```

Note that there two different notions of startup time: from jvm
instantiation, and from before init! was called. This maintains the two
separately so we can diagnose if class load time gets longer
independently of amount of work we do during startup itself
2026-01-27 10:03:20 -06:00
Edward Paget
b8ed3bd4d0 feat: support remote sync for NativeQuerySnippets (#68497)
* feat: support remote sync for NativeQuerySnippets

When the Library collection is remote-synced, all NativeQuerySnippets
and their collections (snippets namespace) are automatically tracked
for remote sync. No separate setting is needed - syncing is tied
directly to the Library collection's is_remote_synced status.

Update the FE to use the declarative approach to refresh dirty state
when snippets are modified and update the library dirty state indicator
to turn on when any snippet or snippet collection is modified.

* fix: deletion of snippets/transforms collections

Fixes a bug where collections in the special namespaces were not cleaned
up after changing branches.

* fixup! don't double create entries

* fixup! transaction scope for test on mysql
2026-01-27 08:38:10 -06:00
Rodrigo López Dato
5486894ab8 Allow [::1] and 127.0.0.1 origins by default for cross-origin requests + support IPv6 origins (#68697)
Allow [::1] origin by default for cross-origin requests
2026-01-27 10:46:56 -03:00
Sébastien
8bafab3e0f Skipping first sso request if possible in EAJS/Modular Embedding (#68679)
skipping first sso request if possible in eajs
2026-01-27 14:04:41 +01:00
Romeo Van Snick
0b8c5cd5a3 Show empty schemas in transform target and table metadata (#68592)
* Show empty schemas when picking a transform target

* Use listSyncableDatabaseSchemas endpoint in data structure

* Handle empty schemas

* Add repro for metabase#68378

* Move transforms tests to new folder

* Split off transforms reproductions into separate specs
2026-01-27 08:15:42 +00:00
github-automation-metabase
9c95c11b7b Update translations 2026-01-27 (#68720)
* Update translation sources 2026-01-27

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-27 06:21:24 +00:00
github-automation-metabase
3a8eae8a39 Auto-update documentation for master (#68713)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-26 23:38:22 -05:00
Ngoc Khuat
b98eb79b38 Flip mariadb during table editing support check (#68171) 2026-01-27 03:27:25 +00:00
Fraser
7d6d5b35a3 Use named exports in common components code (#67779) 2026-01-27 13:34:04 +13:00
Fraser
bc82a001ee Use named exports in visualizations folder (#67058) 2026-01-27 13:26:47 +13:00
Nathan Voxland
7f98271a59 Don't have a queue_message model since it's an implementationd detail 2026-01-26 17:04:26 -06:00
Nathan Voxland
8cc219994d Merge remote-tracking branch 'origin/master' into persistent-queue 2026-01-26 16:44:09 -06:00
kevinkelleher12
0b7737980d Reduce bundle size by removing import of enormous character sizes constant (#68700) 2026-01-26 14:50:03 -07:00
Nathan Voxland
84168dbf05 Merge remote-tracking branch 'origin/master' into persistent-queue
# Conflicts:
#	resources/migrations/059_update_migrations.yaml
2026-01-26 15:27:21 -06:00
Nathan Voxland
f0a7607b2b Only validate map URLs that changed (#68030) 2026-01-26 14:18:59 -06:00
Nathan Voxland
09d1a5d630 Don't duplicate uploads in admin page (#68077) 2026-01-26 13:53:29 -06:00
dpsutton
c3898889fd try to prevent deadlocks in impersonation tests (#68690) 2026-01-26 13:39:25 -06:00
Edward Paget
233dbfecdc feat: toggle transform dirty status on setting change (#68684) 2026-01-26 12:47:26 -06:00
dpsutton
503108d247 Better logging around token checks (#68625)
* Better logging around token checks

We used to just log we were checking but not give error responses. So it
would look like a ton of token checks for no real reason.

Now includes error responses if any, and also include logs when engaging
the token check circuit breaker, and when it is "half open", when it
lets one real token check happen every 30 seconds to see if the service
is back.

```
2026-01-23 12:26:47,175 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:26:47,186 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:26:49,190 INFO premium-features.token-check :: Error checking token: Connect timed out †
2026-01-23 12:26:49,194 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:26:49,201 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:26:51,205 INFO premium-features.token-check :: Engaging circuit breaker in token check ††
2026-01-23 12:26:51,206 INFO premium-features.token-check :: Error checking token: Connect timed out
2026-01-23 12:27:44,548 INFO premium-features.token-check :: In token check circuit breaker but attempting check
2026-01-23 12:27:44,551 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:27:44,565 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:27:46,574 INFO premium-features.token-check :: Engaging circuit breaker in token check
2026-01-23 12:27:46,575 INFO premium-features.token-check :: Error checking token: Connect timed out

...
2026-01-23 12:32:50,432 INFO premium-features.token-check :: In token check circuit breaker but attempting check †††
2026-01-23 12:32:50,433 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:32:50,444 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:32:52,450 INFO premium-features.token-check :: Engaging circuit breaker in token check
2026-01-23 12:32:52,450 INFO premium-features.token-check :: Error checking token: Connect timed out
```

The highlights are now we include:
- † `Error checkign token: Connect timed out` the error response when
appropriate
- †† `Engaging circuit breaker in token check` when we engage the
circuit breaker to no longer do real token checks
- ††† `In token check circuit breaker but attempting check` indicating
we are doing a real one from the circuit breaker to determine if the
service is restored

* Whew. Lots of stuff

add a namespace to the circuit breaker keyword:
`:token-check/circuit-breaker`. Change the keyword holding
`:token-check/app-db-not-ready` to cause. I had used reason but nothing
checked that.

this is because want to log when a token check fails, but not when it is
- failure due to circuit breaker
- failure due to appdb not ready yet.

token checks can happen anywhere and with an enormous frequency. they
fail before the appdb is setup (we can't check settigns yet) and of
course they fail during the circuit breaker opening. that's the point of
the circuit breaker. So we don't have to log these.

We _do_ want to log other failures.

We also want to do some prometheus metrics. Here's a journey:
You previously couldn't import the prometheus analytics namespace
because analytics.settings required appearance.settings. It does so
because a docstring in analytics settings used to include Metabase in
the string. I removed that so now it says "in order to help us
improve". And then things would be smooth sailing.

Except we had an issue.

```
026-01-23 20:50:03,514 INFO analytics.prometheus :: Starting prometheus metrics collector
2026-01-23 20:50:03,539 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
thread229238 we made the system!
thread229238 and now we are done with the lock!
2026-01-23 20:50:03,607 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,611 ERROR premium-features.token-check :: Error validating token: Failed to initialize Prometheus on port 9,191
2026-01-23 20:50:03,611 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,612 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,614 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,616 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,617 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,618 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,619 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,619 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,653 INFO core.core :: Setting up prometheus metrics
```

We have locking around the system but it is starting tons of times! Lots
of debugging, swearing that this can't happen. but then i finally threw
in my favorite trick: `(clojure.repl/pst (Exception. "how did we get
here"))`. And it turns out we are doing this:

1. token check fails, so we call `prometheus/inc!`
2. inc is helpful, sees system isn't yet setup, and sets it up for us
3. Setup metric system
4. setup metrics in system
5. we hit the following code which gets initial values for labels

```clojure
(defn- initial-labelled-metric-values []
  (for [metric (keys (methods known-labels))
        labels (known-labels metric)]
    {:metric metric
     :labels labels
     :value  (initial-value metric labels)}))
```
6. We hit the following search code about which search we have

```clojure
(defmethod analytics/initial-value :metabase-search/engine-active
  [_ {:keys [engine]}]
  (if (search.engine/supported-engine? (keyword "search.engine" engine))
  1 0))
```

7. This takes us to semantic search:

```clojure
(defmethod search.engine/supported-engine? :search.engine/semantic [_]
  (try
    (supported?)
    (catch Exception e
      (log/warn e "Semantic search engine not supported")
      false)))
```

8. `supported?` here checks to see if you support a particular search
impelementation, which of course depends on _YOUR FEATURES_.
9. Checking features fails, so we should increment our prometheus
counter
10. the system is not yet initialized yet. Let's initialize it. (this is
also step 2)

So I have added a simple `inc-if-initialized!` function. It's not
important if the system is down. It's ok if these events are lost. The
system will be initialized in core anyways.

```
❯ http get :9191/metrics | grep metabase_token
 HELP metabase_token_check_attempt_total Total number of token checks. Includes a status label.
 TYPE metabase_token_check_attempt_total counter
metabase_token_check_attempt_total{status="failure",} 8.0
```

logs:

```
2026-01-23 22:58:26,668 INFO premium-features.token-check :: Checking with the MetaStore to see whether token '82bf...c3fe' is valid...
2026-01-23 22:58:28,706 INFO premium-features.token-check :: Error checking token: Connect timed out
2026-01-23 22:58:28,750 INFO core.core :: Setting up prometheus metrics
2026-01-23 22:58:28,751 INFO analytics.prometheus :: Starting prometheus metrics collector
2026-01-23 22:58:28,789 INFO premium-features.token-check :: Checking with the MetaStore to see whether token '82bf...c3fe' is valid...
2026-01-23 22:58:30,793 INFO premium-features.token-check :: Error checking token: Connect timed out
2026-01-23 22:58:30,798 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
...

2026-01-23 22:58:53,441 INFO premium-features.token-check :: Checking with the MetaStore to see whether token '82bf...c3fe' is valid... {mb-quartz-job-type=SyncAndAnalyzeDatabase}
...
2026-01-23 22:58:55,445 INFO premium-features.token-check :: Engaging circuit breaker in token check {mb-quartz-job-type=SyncAndAnalyzeDatabase}
2026-01-23 22:58:55,445 INFO premium-features.token-check :: Error checking token: Connect timed out {mb-quartz-job-type=SyncAndAnalyzeDatabase}
```

```
Exception how here??
	metabase.analytics.prometheus/setup! (prometheus.clj:584)
	metabase.analytics.prometheus/setup! (prometheus.clj:576)
	metabase.analytics.prometheus/inc! (prometheus.clj:668)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.analytics.prometheus/inc! (prometheus.clj:665)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.premium-features.token-check/error-catching-token-checker/reify--98262 (token_check.clj:431)
	metabase.premium-features.token-check/check-token (token_check.clj:488)
	metabase.premium-features.token-check/check-token (token_check.clj:484)
	metabase.premium-features.token-check/check-token (token_check.clj:486)
	metabase.premium-features.token-check/check-token (token_check.clj:484)
	metabase.premium-features.token-check/eval98325/*token-features*98348--98349 (token_check.clj:534)
	metabase.premium-features.token-check/eval98325/fn--98353 (token_check.clj:529)
	metabase.premium-features.token-check/has-feature? (token_check.clj:575)
	metabase.premium-features.token-check/has-feature? (token_check.clj:569)
	clojure.lang.Var.invoke (Var.java:386)
	metabase.premium-features.defenterprise/check-feature (defenterprise.clj:41)
	metabase.premium-features.defenterprise/check-feature (defenterprise.clj:35)
	metabase.premium-features.defenterprise/dynamic-ee-oss-fn/fn--71956 (defenterprise.clj:53)
	metabase.search.semantic.core/eval180600/fn--180601 (core.clj:58)
	clojure.lang.MultiFn.invoke (MultiFn.java:229)
	metabase.search.core/eval139302/fn--139304 (core.clj:77)
	clojure.lang.MultiFn.invoke (MultiFn.java:234)
	metabase.analytics.prometheus/initial-labelled-metric-values/iter--97802--97808/fn--97809/iter--97804--97810/fn--97811 (prometheus.clj:521)
	clojure.lang.LazySeq.force (LazySeq.java:50)
	clojure.lang.LazySeq.realize (LazySeq.java:89)
	clojure.lang.LazySeq.seq (LazySeq.java:106)
	clojure.lang.RT.seq (RT.java:555)
	clojure.core/seq--5488 (core.clj:139)
	clojure.core/concat/fn--5579 (core.clj:727)
	clojure.lang.LazySeq.force (LazySeq.java:50)
	clojure.lang.LazySeq.realize (LazySeq.java:89)
	clojure.lang.LazySeq.seq (LazySeq.java:106)
	clojure.lang.Cons.next (Cons.java:41)
	clojure.lang.RT.next (RT.java:733)
	clojure.core/next--5472 (core.clj:64)
	clojure.core/next--5472 (core.clj:64)
	metabase.analytics.prometheus/setup-metrics! (prometheus.clj:546)
	metabase.analytics.prometheus/setup-metrics! (prometheus.clj:533)
	metabase.analytics.prometheus/make-prometheus-system (prometheus.clj:60)
	metabase.analytics.prometheus/make-prometheus-system (prometheus.clj:55)
	metabase.analytics.prometheus/setup!/fn--97866 (prometheus.clj:591)
	metabase.analytics.prometheus/setup! (prometheus.clj:590)
	metabase.analytics.prometheus/setup! (prometheus.clj:576)
	metabase.analytics.prometheus/inc! (prometheus.clj:668)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.analytics.prometheus/inc! (prometheus.clj:665)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.premium-features.token-check/error-catching-token-checker/reify--98262 (token_check.clj:431)
	metabase.premium-features.token-check/check-token (token_check.clj:488)
```

* module config fixup
2026-01-26 12:26:48 -06:00
bryan
a45d9203f1 Fix flaky GeoJS-dependent tests by mocking external service (#68623) 2026-01-26 10:34:20 -07:00
William
163180e8d9 Delete from cache in batches of 1000 (#68622)
There's apparently an instance on cloud that is trying to remove 70k queries from the cache at once, and postgres
doesn't allow 70k params to a query.  Batching the deletes in groups of 1000 should fix that.
2026-01-26 11:31:02 -06:00
Timofey Kachalov
b81aa809ad feat(sdk,embed-js): Add content translations for Collection/MetabaseBrowser components (#68608) 2026-01-26 21:07:55 +04:00
Jakub Chodorowicz
78efb4247b Gdgt 1557 migrate eslint from deprecated rulesdir to custom plugin (#68570) 2026-01-26 17:27:36 +01:00
Copilot
e51a02cd56 Refactor .styled files to CSS modules with CSS variables (#66851)
* Refactor batch 1: Convert simple styled files to CSS modules (10 files)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

* Refactor batch 2: Convert more simple styled files to CSS modules (8 files)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

* Refactor batch 3: Convert files with color() functions to CSS modules (5 files)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

* misc fixed

* lint fix

* Revert breakpoint changes

* prettier

* color fixes

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-01-26 08:14:38 -07:00
John Swanson
f8d4a239b3 populate here and below for transforms (#68614)
[UXW-2828: collection/:id/items API does not return transforms](https://linear.app/metabase/issue/UXW-2828/collectioniditems-api-does-not-return-transforms)
2026-01-26 05:30:47 -08:00
Sébastien
ae05f0bab7 Fixed missing bg color for dashboards (#68673)
fixed missing bg color for dashboards
2026-01-26 13:20:41 +01:00
Fraser
e2132ed193 use named exports in admin folder (#67771) 2026-01-26 23:12:47 +13:00
Fraser
50e9d524d6 Use named exports in query_builder code (#67780) 2026-01-26 23:12:34 +13:00
Fraser
fbd16c232b Use Metabase Bot GitHub App to create PR (#68664) 2026-01-26 23:12:17 +13:00
Romeo Van Snick
123f2dafd2 MBQL lib helpers for e2e tests (#68278)
* Rename file containing jsx to .jsx

* Add e2e helpers to build metadata provider

* Split up metadata helpers

* WIP

* Add more direct createTestQuestion helper

* Replace test

* Build cljs for tests

* Export type

* Only require entities in the state for getMetadata

* Just pass state to getMetadata

* Move EntitiesSchema to metabase/schema

* Wrap mbql e2e helpers in promise

* Split off getMetadataWithoutSettings

* Use getMetadataWithoutSettings to get metadata from state

* Build entities state manually

* Simplify wrapper

* Fix metadataProvider

* Add createTestJsQuery wrapper for cypress

* Use plain promises and fetch

* Allow passing GetMetadataOpts to createTest(Native)JsQuery directly

* Improve createTestQuestion types

* Make use of createTestJsQuery in test

* Reduce nest in createTestQuestion

* Use simplified createTestQuestion

* Split up mbql helpers

* Fix card metadata call

* Use correct card endpoint

* Pass missing options

* Convert another more complex test to createTestQuestion

* Fix types

* Use static ids for defaults to avoid import loop

* Fetch more tables by default

* Build cljs in embedding tests

* Build cljs in component tests

* Prepare backend env

* Add plugin so we can avoid building CLJS everywher

* Avoid building cljs where not needed

* Fix types

* Rename query helpers

* Split up helpers

* Compile cljs in stress tests
2026-01-26 19:54:16 +11:00
metabase-bot[bot]
16504fd3c8 [chore] Update E2E test timings with recent data (#68665)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-26 21:50:07 +13:00
Romeo Van Snick
997b8d898e Respect abbreviate date style and be defensive around missing settings (#68661)
* Respect date_abbreviate when formatting date

* Respect abbreviate setting in month format too

* Add unit tests for abbreviated formats

* Add unit test for empty formatting settings

* Add repro for metabase#68574

* Add formatting settings unit tests
2026-01-26 15:50:42 +11:00
Alexander Polyankin
ceb518ab4b Dependency diagnostics - update the url, reset page on filter change, fix visibility checks (#68650) 2026-01-25 21:53:08 -05:00
Fraser
0ed6c4deed Link Claude Bugfix PR to Linear issue (#67710) 2026-01-26 10:44:24 +13:00
Sloan Sparger
6c09fca355 Fix NativeQueryEditor's action buttons (#68638)
fix position of buttons for native query editor
2026-01-24 20:34:41 +00:00
Aleksandr Lesnenko
049526c61c Cleanup (#68648)
cleanup
2026-01-24 09:40:18 -06:00
William
a799178420 Python transforms have dependencies (#68572)
The existing transform dependencies code only worked with query-based transforms (mbql or native).  This extends that
code to work with python transforms as well.
2026-01-24 02:34:24 -06:00
Maksym Yakubych
f7b82d5c54 fix: word wrap overflows row when reordering in dashboard table card (#68566) 2026-01-24 00:37:00 -03:00
Anderson
a51d1179d3 Disallow editing transforms when remote sync is read-only (#68380)
* Read-only: Adjust transform header menu options / Remove edit definition button / Run tab updates

* Make Settings tab read-only

* fix remote sync setup in e2e test

* Do not allow creating a new transform

* Make Python library not editable

* Hide edit definition in mbql transform view page

* Fix e2e

* Group e2e tests to improve performance
2026-01-24 01:52:27 +00:00
metamben
cbed2e45a8 Follow up on QUE-2999: move filtering to the database (#68635) 2026-01-23 23:45:05 +00:00
Timothy S. Dean
418d7a0317 Tweak data loading behavior for a test after MySQL 9.6.0 release (#68634)
Closes DEV-1289

### Description

Within the last day or two, `metabase.query-processor-test.remapping-test/self-referencing-test` began failing on MySQL Latest. I hypothesize this has to do with the [latest release](https://dev.mysql.com/doc/relnotes/mysql/9.6/en/news-9-6-0.html) fixing an unknown bug around batch inserts in InnoDB and the deprecation of a recusive [sic] fk-related flag.

The error is thrown not in the test conditions, but in the test setup -- MySQL apparently now checks foreign key constraints row-per-row even on a batch insert.

This adds a flag that the test can set which changes the test data-loading behavior to disable the FK check before insertion and re-enable it after.
2026-01-23 15:56:20 -07:00
Gabriel Moreno
3bce633480 Library empty state: display content in the page body (#68628)
* feat: create library empty state

* refactor: use new designs

* refactor: fix library creation

* fix: paper shadow

* fix: e2e
2026-01-23 18:49:35 -04:00
Gabriel Moreno
48327532c5 More Data Studio UX improvements & QoL fixes (#68546)
* fix(UXW-2752): remove unwanted padding on data structure fields tab group

* fix(UXW-2707): remove double border on job transforms section

* feat(UXW-2718): add horizontal layout for schedule controls

* feat(UXW-2709): fix spacing in the segments empty state

* fix(UXW-2780): long text overflow in user input

* fix(UXW-2710): set proper placeholder text on empty python library first load

* feat(UXW-2767): rename 'New collection' to 'Transform folder'

* refactor: blow grid & use `Ellipsified` instead
2026-01-23 18:03:17 -04:00
Anderson
26f71cfeb5 Fix SQL editor scrolling on Transform pages (#68107)
* Fix SQL editor scrolling on Transform pages

* Fix e2e test for question editor

* Fix python transform scrolling

* Fix lint

* Fix view-only transform content height
2026-01-23 18:42:24 -03:00
Braden Shepherdson
3d4e44b776 [deps] After a sync, re-analyze all dependents of updated tables (#68621)
Closes QUE-2984.

Adds an event handler for when a DWH sync is completed, which checks all its tables and fields for
their latest update times, and re-analyzes all cards which depend on tables updated since the last analysis.
2026-01-23 21:01:41 +00:00
Brad Anderson
86f3e524ba Fix UXW-2759 - Snippet edits in data studio are not saved (#68565) 2026-01-23 15:29:42 -05:00
Nathan Voxland
056d61238e If a dashboard is back to just one tab, auto-assign all cards to that tab (#68201) 2026-01-23 14:22:12 -06:00
Maksym Yakubych
926610da14 fix: custom Logo isn't loaded properly on User Invite Email (#68476) 2026-01-23 11:44:43 -08:00
Alexander Polyankin
75251f933a Fix text wrapping in dependencies (#68615) 2026-01-23 19:28:48 +00:00
Nemanja Glumac
d959d54aec Remove cache cleanup CI action (#68521) 2026-01-23 20:25:23 +01:00
Edward Paget
0933b7378f feat: support remote-syncing measures (#68392)
* feat: support remote-syncing measures

Add remote-sync support for measures, following the same pattern as segments:

- Add :model/Measure spec to remote-sync-specs with hybrid identity,
  parent-table eligibility, and event tracking
- Update measure permissions to check remote-sync/table-editable? for
  can-write? and can-create? (replacing superuser-only derive)
- Add batched hydration for :can_write on measures
- Add measures to serdes/descendants for Table so they export with parent
- Add tests for measure import/export tracking in impl_test.clj

On the Frontend creates a new data-driven approach to setting up the
middleware listener for changes that cause us to refresh dirty-state.

* fixup! typecheck
2026-01-23 13:17:01 -06:00
Edward Paget
e3b200b319 fix: flakey ec keypair test (#68591)
* fix: flakey ec keypair test

* fixup! do crypto in a delay
2026-01-23 13:15:00 -06:00
Edward Paget
fb9c0e4499 fix: derive events remote-sync needs in oss code (#68590) 2026-01-23 13:14:51 -06:00
Nemanja Glumac
40522b6cba Remove unused lodash types (#68593) 2026-01-23 19:26:18 +01:00
metamben
b6edd15de2 Stop reporting errors on archived or inaccessible entities (#68613)
Closes QUE-2999
2026-01-23 12:52:32 -05:00
lbrdnk
16042f45c7 Use macaw options, add parsed-query wrapped (#68466)
* Hoist macaw impl from query analyzer

* Use macaw-opts in bigquery module

* Use macaw-options in sqlserver

* Use macaw-options in sql driver

* Remove require

* Comment

* Test

* Update test

* Update macaw version

* Best effort support for bigquery

* Make test driver specific

* Remove final-not-reserved

* Not allowed on clickhouse only

* Clickhouse exception test

* best effort opts on api

* Remove final-non-reserved

* Remove requires

* driver.u/parsed-query

* Use parsed-query

* parsed-query

* ch test

* throw

* Lint against incorrect Macaw usage (#68568)

* Remove now unused function

* Shutdown loud exceptions for now

* Shutdown ch test

* Update test

---------

Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2026-01-23 18:37:06 +01:00
Riley Thompson
b28ab0ec1d Revert ClickHouse from 0.9.5 to 0.8.4 (#68502)
* revert to 0.8.4

* disable test
2026-01-23 17:18:22 +00:00
github-actions[bot]
add8906504 Fix: Keyboard navigation annoyance in command palette (#67317)
Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
2026-01-23 11:33:33 -05:00
dpsutton
3345365546 handle empty error message (#68581)
Fixes https://github.com/metabase/metabase/issues/68578

This issue is not about the stack overflow per-se but blowing up on a
string includes:

```javascript
{
  "app": "metabase",
  "time": "2026-01-22T12:08:53.660601485Z",
  "stream": "stderr",
  "app_version": "v1.57.10-X01",
  "message": "Exception in thread \"Thread-41\" java.lang.NullPointerException: Cannot invoke \"Object.toString()\" because \"s\" is null
at clojure.string$includes_QMARK_.invokeStatic(string.clj:377)
at clojure.string$includes_QMARK_.invoke(string.clj:373)
at metabase.app_db.cluster_lock$retryable_QMARK_.invokeStatic(cluster_lock.clj:27)
at metabase.app_db.cluster_lock$retryable_QMARK_.invoke(cluster_lock.clj:19)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invokeStatic(cluster_lock.clj:87)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invoke(cluster_lock.clj:65)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invokeStatic(cluster_lock.clj:79)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invoke(cluster_lock.clj:65)
at metabase.search.task.search_index$init_BANG_.invokeStatic(search_index.clj:36)
at metabase.search.task.search_index$init_BANG_.invoke(search_index.clj:32)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.lang.Thread.run(Unknown Source)",
  "namespace": "hosting-eb9b3875e12d465a",
  "container": "metabase",
  "cluster": "metabase-1",
  "_p": "F"
}
```

The error message itself comes from a stackoverflow which perhaps does
not have a message? Either way, it's possible for this to be missing so
be a bit defensive
2026-01-23 10:04:56 -06:00
Sébastien
862dc50c64 Fix ChartTypeDropdown overflowing (#68455)
* Forcing overflow policy on ChartTypeDropdown

* tpyo

* refactoring to enable testing this with loki

* fixed story

* loki

* screenshot

* removed useless unit test
2026-01-23 16:08:37 +01:00
Nicola Mometto
0941091421 ensure common.py library is always available (#68603)
* fix: ensure common python library is always defined

* chore: e2e test

* fix: empty rollback

* fix: empty source

* fix: text
2026-01-23 15:01:18 +00:00
Alexander Polyankin
0bd69823a4 Show view_count for models and metrics in dependencies (#68588) 2026-01-23 17:42:57 +03:00
Alexander Polyankin
6a01533ca7 Use MBQL lib for matching field refs in ValueSourceModal in parameters (#68431) 2026-01-23 17:42:06 +03:00
Nemanja Glumac
7d18a1b5a6 Unset the premium token for E2E tests (#68533) 2026-01-23 13:54:21 +01:00
github-automation-metabase
0bf7e41984 Auto-update documentation for master (#68589)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-23 07:47:03 -05:00
Sébastien
95a25e4a3e fix proper bg color for embedded dashboards with custom theme (#68539) 2026-01-23 13:00:22 +01:00
Dan Stone
a2c4eef9de Revert the revert of column validation for incremental transforms (#68460)
Filter extract-columns endpoint to only return numeric and temporal columns
The extract-columns-from-query function is used to populate the incremental
filter dropdown for native SQL transforms. Previously it returned all columns
without filtering on type, leading to undefined behaviour when unsupported
column types were selected.

This change filters the results to only include columns with types supported
for incremental checkpointing:
- Temporal types (timestamp, timestamp with timezone)
- Numeric types (integer, float, decimal)

Text, boolean, and other unsupported types are now filtered out, matching
the behaviour of MBQL and Python transforms which already filter columns
client-side.

Updated documentation to clarify this endpoint is specifically for incremental
transform checkpoint column selection.

Also validates that transform POST/PUT conform to this rule and you are unable to update the transform to have
a filter column of an unsupported type.

Reverts the revert of https://github.com/metabase/metabase/pull/67686
2026-01-23 11:24:09 +00:00
Chris Truter
2f81937643 Fix data format for TODOs in style guides (#68598) 2026-01-23 13:13:30 +02:00
Sloan Sparger
48bf58b162 Cleanup from #68433 (#68481)
fix ai feedback that came after PR close :'/
2026-01-23 02:33:48 +00:00
Egor Grushin
761a7cf01e GDGT 1533 improve discoverability of python library in transforms UI (#68523) 2026-01-23 00:55:37 +00:00
Timothy S. Dean
8a76f71003 Remove find-column-for-name (#68382)
Remove find-column-for-name
2026-01-22 16:06:41 -07:00
Maksym Yakubych
fd90d13ae3 fix: custom brand color not consistently applied on Enterprise UI elements (#68484) 2026-01-22 22:56:00 +00:00
Maz Ameli
a62aab3f1b Rename Data Studio Library +New menu action labels (#68162)
* Rename Data Studio Library +New menu action labels

Update the menu item labels in the Data Studio Library's +New button:
- "Publish a table" → "Published table"
- "New snippet" → "Snippet"
- "New snippet folder" → "Snippet folder"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* prettier

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 22:39:54 +00:00
metamben
bafd49ee17 Add options to the /graph/dependents endpoint (#68573) 2026-01-22 21:58:19 +00:00
Edward Paget
1f0b461d6f feat: support remote sync transforms in FE (#68306)
* feat: support remote sync transforms in FE

1. Updates the DataStudioLayout to show transform dirty state

   We get the orange dot next to Transforms if transforms or transform
   collections are dirty.

2. Update the all changes view to include transforms

   Also includes their collection heirarchy if the transforms sync
   setting is enabled

3. Add the transforms sync setting

   To both the remote sync admin page and the Set up git sync modal in
   the data studio

* fixup! refresh transforms after sync

* fixup! data studio test feedback

* fixup! refactor failing test to troubleshoot debugging
2026-01-22 14:33:00 -06:00
metamben
1712274b85 Normalize transforms metadata (#68490) 2026-01-22 23:22:39 +03:00
Timofey Kachalov
ea203102e6 Don't show CORS settings in OSS/Starter editions (#68564) 2026-01-23 00:14:05 +04:00
Edward Paget
3c72591b17 feat: add Slack Connect SSO provider (#67955)
* feat: add Slack Connect SSO provider

Add enterprise Slack Connect SSO integration using the OIDC infrastructure:

- Slack Connect provider: OAuth2/OIDC flow for Slack workspace authentication
- Settings: configuration options for Slack client ID, secret, and auth modes
- User provisioning: automatic user creation from Slack identity
- API endpoints: SSO initiation and callback handling
- Analytics: usage tracking for Slack Connect feature

Slack Connect allows users to authenticate via their Slack workspace,
with support for both SSO-only and link-account authentication modes.

* fix: session reset after auth

* fixup! avoid email clash

* fixup! wrong value in sso settings

* fixup! cleanup tests

* fixup! fix test

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-01-22 10:57:12 -08:00
github-automation-metabase
9a19a5e4f0 [chore] Update llms.txt for master (#68561)
Update llms.txt and llms-full.txt (master)

Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.

🤖 Generated automatically by llms-txt-generate workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-22 18:20:04 +00:00
Sloan Sparger
f387d4aca4 [Metabot] Add close button back to data studio sidebar (#68487)
allow metabot to be closed in data studio
2026-01-22 11:33:21 -06:00
github-automation-metabase
1bb6f6a74a Update translations 2026-01-22 (#68557)
* Update translation sources 2026-01-22

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-22 17:19:01 +00:00
Nicolò Pretto
2ad4292465 fix(embed-homepage): rename static embed to guest embed (#68338) 2026-01-22 16:37:02 +00:00
github-automation-metabase
37c3758748 Auto-update documentation for master (#68524)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-22 09:26:48 -05:00
Jeff Bruemmer
ae9cad5c58 docs - note on ee vs oss path (#68210) 2026-01-22 09:09:05 -05:00
John Swanson
bd14e14974 Reenable deactivated tenants when autoprovisioning (#67947)
Previously even when autoprovisioning was on, you could not log into a
deactivated tenant (either as a new user or an existing user with that
tenant).

This changes the behavior to be more consistent. Just as a deactivated
user can log in when provisioning is on (and their user gets
reactivated), a deactivated tenant's users can still log in, but doing
so reactivates the tenant.
2026-01-22 05:10:23 -08:00
Jakub Chodorowicz
85319217cd Gdgt 1273 add snowplow events to bulk metadata features (#68409)
* add data studio library filtering events

* add bulk properties and unpublish event

* add bulk sync events

* add search event

* add assertions on events in e2e tests

* add search debounce

* remove unncessery comment

* update event names

* track filter searches with data_studio_table_picker_search_performed

* refactor tracking function

* guard and log event only for ConcreteTableId

* log search when started fetching

* fix events not fired

* fix event not fired on first search
2026-01-22 12:30:26 +01:00
Nicola Mometto
240acb4782 add started-at filter to task runs page (#68279)
* WIP: add started-at filter

* fix: kondo

* fix tests

* GDGT-1520 add a started at filter

* GDGT-1520 add a comment

* GDGT-1520 fix typing issues

* GDGT-1520 addressing PR comments

* GDGT-1520 addressing PR comments

* GDGT-1520 fix a tests after changing a text

---------

Co-authored-by: Egor Grushin <egor@metabase.com>
2026-01-22 09:49:15 +00:00
Jakub Chodorowicz
e6bc40c223 add analytics skill (#68419) 2026-01-22 09:36:42 +01:00
bryan
76fcb4d573 Fix transforms module to trigger driver tests + promote pg (#68432) 2026-01-21 16:30:15 -07:00
Arkadi Yaroslavtsev
a92317dd27 Add Anchor Links to Documents (#67940)
* Add AnchorLinkButton component for document anchor links

- Add AnchorLinkButton component that copies URL to clipboard on click
- Shows 'Copied!' tooltip feedback using Mantine useClipboard hook
- Follows same pattern as CommentsButton for consistent styling
- Add unit tests for the component

* Add AnchorLinkMenu component for left-side anchor link hover

- Add AnchorLinkMenu floating menu for document blocks
- Uses createPortal for positioning (same pattern as CommentsMenu)
- Positioned on left side of blocks using floating-ui
- Shows/hides based on hover state via show prop
- Add unit tests for the component

* Add AnchorLinkMenu to document node views

- Add documentWithAnchor URL helper to generate shareable anchor URLs
- Update Heading, Paragraph, and Blockquote node views to render AnchorLinkMenu
- AnchorLinkMenu appears on the left side on hover
- CommentsMenu on the right side remains unchanged
- Each node view now uses two useFloating instances for positioning

* Add scroll-to-anchor for document URLs with hash

- Add E2E tests for anchor links functionality
- Implement scroll-to-anchor when navigating to document with #blockId hash
- Tests cover: hover shows anchor icon, copy to clipboard, scroll to block
- Regression test ensures CommentsMenu still works on right side

* Fix scroll-to-anchor dependency arrays for navigation edge cases

- Add documentId to scroll effect dependencies to re-run when navigating
  between documents with the same anchor hash
- Add location.hash to reset effect dependencies to properly reset flag
  when navigating via back button or changing anchors

* Fix accidental logo replacement and E2E blockquote test

- Restore original Metabase logo SVG (was replaced with red star debug graphic)
- Fix E2E test: use find('blockquote') instead of findByRole('blockquote')
  since native blockquote elements have no implicit ARIA role

* Fix scroll-to-anchor reliability and empty line behavior

- Implement retry mechanism for scroll-to-anchor to ensure target element exists
- Add highlight animation when scrolling to anchor
- Hide anchor link and comment menus on empty lines (Heading, Paragraph, Blockquote)

* Fix selector mismatch for scroll-to-anchor

- Add data-node-id attribute to NodeViewWrappers in Heading, Paragraph, and Blockquote
  extensions so they can be queried by DocumentPage
- Update DocumentPage to query using [data-node-id] selector instead of internal _id attribute
- Remove unused ID_ATTRIBUTE_NAME import in DocumentPage

* Fix highlight animation color variable

- Replace non-existent --mb-color-brand-alpha-25 with --mb-color-brand-light
- Ensure highlight animation is visible when scrolling to anchor

* added anchor links to lists and code blocks. some bugs fixes.

* make sure scroll-to-anchor observer is correctly initialized

- Refactor scroll-to-anchor logic to ensure smoother navigation
- Optimize highlight animation visibility during scrolling
- Adjust anchor link behavior on empty lines for better user experience

* small fixes

* clean up

* fixes and cleanup

* e2e test fixes

* fixed e2e test

* Leave anchor links only for header blocks

* Fix alignment

* Review fixes

* Fix unit tests

---------

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2026-01-22 02:03:04 +03:00
bryan
087a317f70 Fix ci-report output formatting issues (#68505) 2026-01-21 15:50:57 -07:00
Denis Berezin
c63fd746d8 Uxw 2633 copy cells from table (#68429)
* UXW-2633 fix sorted table values copy-paste

* Add e2e test
2026-01-22 01:24:12 +03:00
dpsutton
f29a446aab fix materialized views test (#68509)
https://github.com/metabase/metabase/pull/68190 did:

> Treats a 0 value of n_live_tup as NULL, due to confusion reported when
> auto analyze thresholds have not been met on a table.

I think what's happening is this is trying to suss out "i don't know"
and not give misleading information. When there are no stats pg would
report there are 0 rows rather than saying i don't know. So we toss away
these unreliable 0 count estimations.

This test flakes 7% of the time. Our hypothesis is that stats are empty
7% of the time so this row count estimation now gets removed.

By default the schema is `:estimated_row_count (mt/malli=? [:maybe
:int])` which was being clobbered with
`{:estimated_row_count (mt/malli=? int?)}` So the fix is to just not
clobber
2026-01-21 16:07:45 -06:00
Edward Paget
d26bf4e454 feat: support transforms in remote sync (#68255)
* feat: support transforms in remote sync

1. Serialize Transforms as Collection Items

   Transforms were previously serialized as a top-level item, but this
   moves them to be serialized as a child of the collection they are
   member of. This also fixes an error in their serdes/dependencies
   implementation where it did not include the parent collection leading
   to deserialization issues.

2. Enforce Remote-Sync write rules

   Adds implementations of the model interface permissions methods for
   transforms that enforce the can-write? = false and can-create? =
   false rules when remote-sync is in read-only mode.

3. Add a setting to control whether transforms are synced

   Transforms are globally synced not synced via collections, so this
   adds a new boolean setting that controls whether they are synced on
   instances in read-write mode. Like all other content transforms are
   always synced from the remote source if the instance is in read-only
   mode.

4. Add a new spec-based configuration system for models

   Models we want to make remote-syncable have a complicated, but still
   data-driven system to allow you to specify their remote-sync behavior
   and have that automatically setup in a single place the
   `metabase-enterprise.remote-sync.spec` namespace.

* fixup! test with wrong folder

* fixup! not handling archived transform collections

* fixup! clean up aliases
2026-01-21 15:29:27 -06:00
Denis Berezin
7aa18ae448 Fix flaky test that uses readonly db that lacks permissions (#68417) 2026-01-22 00:15:27 +03:00
Timothy S. Dean
97da3d7c7b Migration follow-up fix to #68100 (#68498)
Move a migration from the v59 file to the v56 file, as we intend to backport it that far.
2026-01-21 14:15:12 -07:00
Aleksandr Lesnenko
10e8a68cf5 Data Analysts user group (#67770)
* basic analyst role

* analyst role

* Backend for data analyst role

* Fixup frontend to work with Backend

The dedicated analyst endpoints have been removed:
- `GET /api/user/analysts` -> Use `GET /api/user?is_data_analyst=true`
- `POST /api/user/analysts/:id` -> Use `PUT /api/user/:id` with `{ is_data_analyst: true }`
- `DELETE /api/user/analysts/:id` -> Use `PUT /api/user/:id` with `{ is_data_analyst: false }`

These hooks no longer exist:
- useListAnalystsQuery
- useAddAnalystMutation
- useRemoveAnalystMutation

New Patterns:

Listing analysts:
```
// Before
const { data } = useListAnalystsQuery();

// After
const { data } = useListUsersQuery({ is_data_analyst: true });
```

Adding an analyst:
```
// Before
await addAnalyst(userId).unwrap();

// After
await updateUser({ id: userId, is_data_analyst: true }).unwrap();
```

Removing an analyst:
```
// Before
await removeAnalyst(userId).unwrap();

// After
await updateUser({ id: userId, is_data_analyst: false }).unwrap();
```

Type Changes:

The field is_analyst has been renamed to is_data_analyst everywhere:

- User.is_data_analyst (was is_analyst)
- UpdateUserRequest.is_data_analyst (was is_analyst)
- ListUsersRequest.is_data_analyst (new field for filtering)

* kondo

* circular dep

* fix backend not compiling

* use the actual role

* analyst management, glossary access for admins

* various data studio access

* access to library

* drop custom analyst seats management ui

* automatic perms group

* fix tests

* specs

* permissions

* fix lints, add migration rollbacks

* data analysts can ALWAYS view table metadata

implemented for:

- search
- `table/can-read?`

* Also remove `can_access_data_model`

* Revert "Also remove `can_access_data_model`"

This reverts commit 03af432ccb.

* fix more tests

* more tests

* snapshots

* remove redundant checks

* everyone can see

* hide data analyst group for OSS

* Make data analysts a normal group on OSS

* Automatically provide data analysts with perms

Data analysts automatically get manage-table-metadata permissions on
every table/database.

* only disable setting some perms for data analysts

* kondo

* oops, one more kondo

* test fixes

* specs, fixes

* more specs, fixes

* cleanup

* more test fixes

* fix module config

* ci

* doh, fix test

* more test whack-a-mole

* move data analyst group to the top of perms views

* review

* ci

* Turn DA into a regular group when feature missing

instead of just on OSS.

The goal is:
- OSS: a previously existing Data Analysts group is a regular group with
configurable permissions. The real Data Analysts group is invisible and
has no members.
- EE without the token: same as above
- EE with the token: the real Data Analysts group is visible.

* oops, remove unnecessary require

* another one

* fix membership API

* fix a couple more tests

* macro gets a !

* fix `fetch-groups-test`

* ci

* ci

* ci

* ci

* fix collection perm in migration

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-01-21 12:43:35 -08:00
Dan Meyer
209a34b102 ci: Enable fail-fast for BigQuery and Snowflake driver tests (#68199)
Add :fail-fast? true to BigQuery and Snowflake test-args, matching the
existing Redshift configuration. This stops test execution on first
failure, saving CI time and resources.
2026-01-21 20:27:03 +00:00
William
a6df84c136 Bump toucan2 version to fix dashboards sometimes failing to load (#68494)
If the first table mentioned by a dashboard has no fields (presumably because the table and its field are all
inactive), /api/dashboard/<id>/query_metadata would fail due to a toucan2 bug.  This bumps toucan2 to fix the bug and
adds a test to verify that this case now works.
2026-01-21 20:18:30 +00:00
Riley Thompson
adb9a5cbf4 Bump dependency analysis version (#68488)
bump dependency analysis version
2026-01-21 19:08:45 +00:00
Phoomparin Mano
d491eb6d51 Apply unified theme object to main app and modular embedding (#68169)
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2026-01-22 01:30:13 +07:00
Cam Saul
0f20f4d2f0 Deduplicate field refs by ignoring :source-field-name unless it matters (#68166)
* Tentative fix for #67808 -- deduplicate by ignoring :source-field-name if possible

* Make sure `:fields` remains a vector

* Add note

* cljfmt
2026-01-21 11:13:14 -06:00
Maksym Yakubych
9304e6cb6e fix: page hangs without a loader when saving a PDF (#68385) 2026-01-21 13:37:44 -03:00
Riley Thompson
21f043d697 Return upstream breaking entities for dependencies (#68282)
* initial work

* fix test

* fix another test

* source entity malli schema

* clean up and add test

* add tests

* clean up

* fix tests

* drop finding_details column

* fix analysis version

* Update enterprise/backend/src/metabase_enterprise/dependencies/models/analysis_finding.clj

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>

* use transaction

* use node-errors refactor suggestion

* use maybe-resolve-join

* add schemas

* add comment

* kondo

* fix test

* initial changes

* remove validate/ prefix

* replace name/message with detail in dependents_errors

* fix test

* kondo

* typo

* Clean up

* add back card types

* remove unused

* add back card types comment

* small adjustment

* Fixes

* Add links

* reuse existing query

* UI

* use detail

* clean up tests

* UI

* UI

* UI

* improve tests

* initial /dependents broken filtering

* UI

* UI

* UI

* UI

* UI

* UI

* UI

* UI

* return full analysis finding error from api

* accept multiple dependent_types and dependent_card_types

* sort by dependents errors

* fix dependents broken parameter test

* fix

* fixes

* fix sorting

* Fix

* fixes

* fixes

* fixes

* fix

* tests

* fixes

* fix

* fixes

* fixes

* fixes

* fixes

* fixes

* add transforms

* fixes

* fix

* Add views

* fixes

* fixes

* basic e2e test

* fixes

* tests

* tests

* tests

* tests

* tests

* fixes

* fixes

* fix mysql distinct counting

* fixes

* fixes

* fix count query

* handle emtpy error detail

* fix i18n parser

* initial pr comments

* refactor dependency-items-args

* address comments

* small changes

* fix flake

---------

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-01-21 11:26:10 -05:00
Sloan Sparger
d6bb46208f [Metabot] Send transforms_codegen profile on transforms pages again (#68433) 2026-01-21 09:09:12 -06:00
Egor Grushin
e2f7cc9d86 GDGT-1516 add datetime formatting to Task Run Monitoring features (#68427) 2026-01-21 15:09:03 +00:00
Oleksandr Solovyov
0880e7297d fix incremental transform tests (#68470) 2026-01-21 17:04:54 +02:00
metamben
4f23bc973f Prevent exception in cleanup masking the original exception (#68371) 2026-01-21 14:49:43 +00:00
Anderson
1afabc3d01 Allow editing segments and measures when remote sync is read-only and table is unpublished (#68326)
* Still allow editing segments when table is not published

* Allow editing on measures when table is not published
2026-01-21 11:45:19 -03:00
github-automation-metabase
cdf5111a0d Auto-update documentation for master (#68447)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-21 09:13:34 -05:00
Timofey Kachalov
70cf127afd Remove linking between static and simple embedding settings when toggling guest embeds in Admin UI (#68231) 2026-01-21 16:20:30 +04:00
Oleksandr Solovyov
ac421d0a6d transforms: pass full object instead of re-querying db internally (#68456) 2026-01-21 11:45:23 +00:00
Dan Stone
9f5b23ecdd Custom ref schema that reuses the cache (#68379)
Add ref schema caching

Introduces a custom :ref IntoSchema that permits
reuse of Schema objects for references when safe to do so.

Early tests indicate a dramatic reduction in heap retention, after
loading a single dashboard, I see a 10x resident heap reduction from ~300MB to ~30MB.

It should also act as knot tie / runtime combinatorics limiter, so we should not see 'leaky' growth at runtime.

More work could be done as there are still _some_ gaps here.
- Bare pointers (keywords) can still lead to exponential allocation
- We do not cache when :documentation is present on the ref
  (as it would specialise the Schema object delivered for that specific reference)
2026-01-21 10:30:04 +00:00
Sébastien
f8551c9800 Fixed no-literal-metabase-strings eslint rule for export * from './MetabaseThing'; (#68411)
fixed eslint custom rule
2026-01-21 10:42:55 +01:00
Kamil Mielnik
4befb6089f Fix - It's not possible to continue editing a bad transform (#68415) 2026-01-21 09:08:12 +00:00
Romeo Van Snick
c902d22458 Contain layout for notebook preview (#68448)
* Contain layout for notebook preview

* Add repro for metabase#67903
2026-01-21 19:14:00 +11:00
Romeo Van Snick
7451ffcd93 Set max height to native editor and some other refactors (#67896)
* Desrtucture all this.props

* Convert to function component

* Remove the wrapper

* Forward ref in topbar

* Limit resize height

* Pass availableHeight to native query editor

* Move var to constants

* Add more padding

* Rename viewHeight to availableHeight

* Handle unset availableHeight

* Add availableHeight to QueryEditor

* Calculate availble height above the fold

* Resize editor when available size shrinks

* Remove layer of nesting

* Rename calc to get

* Pass availableHeight to sql editor in modal

* Remove resizableBoxProps prop

* Do not resize when closing editor

* Use runQuery from props when availabe

* Sort props and remove unused props

* Clean up setIsNativeEditorOpen

* Remove dispatch from NativeQueryEditor completely

* Move state change out of useEffect

* Pull out resizable box into separate component

* Simplify availableHeight prop

* Move resizable logic into separate component

* Clean up code

* Handle availableHeight being 0 initially

* Make minHeight take preference

* Avoid setting height to Infinity

* Add repro for metabase#59075

* Fix e2e test

* Do not use default export

* Add type to NativeQueryEditor

* Remove unused databases loader

* Remove unused ExplicitSize wrapper

* Remove enity loader wrappers

* Flatten props

* Fix setDatabaseQuery type

* Fix types

* Add className to NativeQueryEditor

* Fix types

* Pull out handler

* Manually update metadata when updating snippet

* Preserve sidebar state if need be

* Fix e2e test

* Fix mock exports

* Fix e2e test

* Do not overwrite availableHeight

* Remove viewHeight prop

* Increase limit

* Fix broken test

* Remove unneeded useHeightAboveFold helper
2026-01-21 06:47:32 +00:00
dpsutton
410471a4d0 Revert transforms changes recently (#68446)
* Revert "Filter incremental transform column listing to supported types only (#67686)"

This reverts commit 735b98d6f8.

* trigger driver changes
2026-01-21 03:16:13 +00:00
Nemanja Glumac
a2b3490355 Run codespell on schedule and auto-fix typos (#68444) 2026-01-21 00:14:41 +00:00
bryan
3b8e1ecaa4 Add mage ci-report command for CI failure analysis (#68319) 2026-01-20 22:23:40 +00:00
Maksym Yakubych
0176c399f9 fix: "Connect to Slack" CTA remains visible after Slack is configured (#68289) 2026-01-20 22:04:41 +00:00
dpsutton
2287567b12 Fix Horror Show fingerprint OOMs (#68391)
* Fix Horror Show fingerprint OOMs

This may likely fix many OOMs that others are seeing. Anyone with large
schema will likely benefit from this.

```clojure
(let [database (toucan2.core/select-one :model/Database :id 2)]
  (metabase.sync.analyze.fingerprint/fingerprint-fields-for-db!
    database (fn [s t] (println "synced " s "for " (:name t)))))
```

This is how we fingerprint fields. DB 2 here is "Horror Show", a
database with 200 tables, each of which has 900 fields in it. This
database has zero rows in it, it it just a large schema.

Syncing this recently has caused huge cpu spikes and then OOM errors
until the instance is killed.

Profiling locally with

```
MB_JETTY_PORT=3091 java "$(socket-repl 6091)" -Xmx2g -jar metabase.jar
```
and visual vm hooked up, I run

```clojure
(let [database (toucan2.core/select-one :model/Database :id 2)]
  (metabase.sync.analyze.fingerprint/fingerprint-fields-for-db!
    database (fn [s t] (println "synced " s "for " (:name t)))))
```

And observe this behavior:
The ram usage approaches the 2gb limit and then bounces there. The CPU
begins to spike erratically and spend 10% of its time in GC.

Taking a heap dump we can see that we have 2.8 million ResultSetMetaData
objects occuping 183 Mb.

The ResultSetMetaData are closed over and kept in the metadata of the
snake hating maps stored in the cached metadata provider.

This brings into stark relief one simple way to fix this: don't use a
caching metadata provider. This PR just raising the body of the
fingerprint-tables-for-db function to not include
`(qp.store/with-metadata-provider (u/the-id database)` . There is no
benefit to caching here as this is an enumeration of the database. It is
by design not meant to reuse anything. If we didn't OOM we would end up
with 200 tables and 200*900 = 180,000 fields in the cache, each of which
was accessed only once.

That is what this PR fixes.

I also followed one other thread: why are we holding so many
ResultSetMetaData objects in memory. This seems to come about from a
change in https://github.com/metabase/metabase/pull/62330 specifically
this line:
https://github.com/metabase/metabase/blob/master/src/metabase/lib_be/metadata/jvm.clj#L63

```clojure
(mu/defn instance->metadata
  "Convert a (presumably) Toucan 2 instance of an application database model with `snake_case` keys to a MLv2 style
  metadata instance with `:lib/type` and `kebab-case` keys."
  [instance      :- :map
   metadata-type :- :keyword]
  (let [normalize (if-let [schema (get metadata-type->schema metadata-type)]
                    (fn [instance]
                      (lib.normalize/normalize schema instance))
                    identity)]
    (-> instance
        (perf/update-keys memoized-kebab-key)
        (assoc :lib/type metadata-type)
        normalize
        u.snake-hating-map/snake-hating-map
        ;; the line below here captures the result coming back from
        ;; toucan and has a closure over
        ;; toucan2.jdbc.read/make-column-thunk which has a closure over
        ;; (.getMetaData rset)
        (vary-meta assoc :metabase/toucan-instance instance))))
```

As it stands without any changes, the instance gets quite unstable and
falls over. If you comment out the `var-meta` form above, the graph
returns to a very normal sawtooth graph of memory usage and
reclaimation. But central to this is that it does not need to retain any
of this memory at all. But without this metadata containing the instance
and db classes, we only cache the table and field data and the
fingerprinting can finish. When we cache this stuff and also
inadvertently keep these db classes, we quite quickly run out of
headroom and the instance becomes unstable and falls over.

* fix kondo lint (removes a legacy usage as well :) 💰
2026-01-20 14:58:56 -06:00
Sloan Sparger
d9b8b9a2c0 [Metabot] Bug fix - animation color for nlq loading state (#68149)
fix animation color for nlq loading state
2026-01-20 14:57:32 -06:00
dpsutton
17f473a9f1 bit more cleanup (#68300)
* bit more cleanup

kept having a few flakes, couldn't consistently get it to pass 45 times
in a row locally. So just simplify it. Don't worry about "in process"
stats. Trying to get the webserver paused in the middle of a request was
occasionally deadlocking, often flaking.

So just calculate the simple ones and it's fine

```clojure
statistics-handler-test=> (clojure.test/run-test server-stats-test)

Testing metabase.server.statistics-handler-test

Ran 1 tests containing 13 assertions.
0 failures, 0 errors.
{:test 1, :pass 13, :fail 0, :error 0, :type :summary}
statistics-handler-test=> (dotimes [_ 100](server-stats-test))
nil
```

Also got rid of the macro that really only existed to collect the forms
into an anonymous function. Everything in-lined and now don't need a
kondo hook, etc

* remove unused alias

* kondo the refers

* reintroduce in-flight metrics

these:
```
(is (prometheus-test/approx= 1 (value! :jetty/requests-active)))
(is (prometheus-test/approx= 1 (value! :jetty/dispatched-active)))
```

Require a mechanism that can pause a request while active, verify that
the requests-active and dispatched active are incremented, and then
carry on. This is all kinda trivial except getting it wrong can
deadlock. Here are 500 successful runs of this test:

```
statistics-handler-test=> (dotimes [_ 100] (server-stats-test))
nil
statistics-handler-test=> (dotimes [_ 100] (server-stats-test))
nil
statistics-handler-test=> (dotimes [_ 100] (server-stats-test))
nil
statistics-handler-test=> (dotimes [_ 100] (server-stats-test))
nil
statistics-handler-test=> (dotimes [_ 100] (server-stats-test))
nil
```
2026-01-20 14:53:30 -06:00
Noah Moss
110cb5bca7 Streaming API response schema for documentation (#68386)
* Streaming API response schema POC

* Narrow a couple schemas

* fix comment

* bump ci

* oops, fix schema placement

* address feedback
2026-01-20 19:30:28 +00:00
Timofey Kachalov
1149c3e30c feat(embed-js): Add a counter-like query parameter for EmbedJS iframe src to allow multiple iframes loading in parallel (#68420) 2026-01-20 22:49:53 +04:00
Dan Stone
735b98d6f8 Filter incremental transform column listing to supported types only (#67686)
Filter extract-columns endpoint to only return numeric and temporal columns

The extract-columns-from-query function is used to populate the incremental
filter dropdown for native SQL transforms. Previously it returned all columns
without filtering on type, leading to undefined behaviour when unsupported
column types were selected.

This change filters the results to only include columns with types supported
for incremental checkpointing:
- Temporal types (timestamp, timestamp with timezone)
- Numeric types (integer, float, decimal)

Text, boolean, and other unsupported types are now filtered out, matching
the behaviour of MBQL and Python transforms which already filter columns
client-side.

Updated documentation to clarify this endpoint is specifically for incremental
transform checkpoint column selection.

Also validates that transform POST/PUT conform to this rule and you are unable to update the transform to have
a filter column of an unsupported type.
2026-01-20 18:00:36 +00:00
Jakub Chodorowicz
359158e594 Gdgt 1312 adjust range selection to work also with schemas and dbs (#68280) 2026-01-20 18:17:50 +01:00
Edward Paget
9a5e8227d0 fix: failing transforms revision test (#68422) 2026-01-20 16:40:22 +00:00
github-actions[bot]
287665a6fa Fix: Actions attached to models inside of Library(synced collection) break remote sync (#68252)
Fixes #68215

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Ed Paget <ed@metabse.coma>
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2026-01-20 10:23:56 -06:00
Jeff Bruemmer
82f16a8528 docs - guest embed locked parameters (#68293) 2026-01-20 10:50:26 -05:00
github-automation-metabase
45b4b682cc Auto-update documentation for master (#68402)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-20 09:58:17 -05:00
Denis Berezin
7a96e1f142 UXW-2497 fix remote-sync flaky test (#68368) 2026-01-20 17:16:05 +03:00
Gabriel Moreno
a48f246c50 Add transform owners and show them in Data Studio (#67840)
* feat: add owner fields

* feat: hydrate owner property on transforms

* feat: extend `start-run` function to accept `user_id` and use it on scheduled transform runs

* feat: implement 'Ownership' section in transform settings page

* test: implement unit specs

* test: add e2e spec

* feat: show owner avatar in transforms list

* Minor clojure improvements

* test: simplify & extend e2e spec

* refactor: simplify avatar usage & change unassigned copy to "No owner"

* refactor: de-duplicate success & error messages

* test: add missing serialization test transform attributes

* test: fix e2e spec by scrolling into view first

* refactor: attribute manual runs to current user rather than owner

* refactor: cleanup

* tests: add missing user id parameter for jobs unit spec

---------

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2026-01-20 10:07:33 -04:00
Sébastien
dd00b33545 Fix tracking event never set to default in embed (#68407)
* fix tracking event never set to default in embed

* added e2e
2026-01-20 14:35:08 +01:00
Jakub Chodorowicz
51eab9a902 add openapi check to ci pipeline (#67854)
openapi check with self healing, all hidden behind ci label
2026-01-20 14:31:43 +01:00
Dan Stone
4b47763109 Restore future in mock client calls so that interrupts are isolated from caller (#68408)
Ensure client-full-response uses future so that interrupts are isolated from caller

An intentional server side .interrupt might leak and cause subsequent
code to fail.

Prior to https://github.com/metabase/metabase/pull/65872 the
client-full-response used a with-timeout, which incidentally put the
http handler in a future (isolating the interrupt).

This commit restores the previous behaviour, in a more intentional way.
2026-01-20 12:59:56 +00:00
github-automation-metabase
d4960babe5 [chore] Update llms.txt for master (#68410)
Update llms.txt and llms-full.txt (master)

Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.

🤖 Generated automatically by llms-txt-generate workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-20 12:57:37 +00:00
Gabriel Moreno
3856fd989e Data Studio UX improvements & QoL fixes (#68320)
* fix(uxw-2711): dependency graph corner radius

* fix(uxw-2706): give snippets a default name

* feat(uxw-2750): use actual link elements for transform list page

* feat(uxw-2750): use actual links for library section layout items

* fix(uxw-2751): prevent transform cancel handler from wiping changes
2026-01-20 08:37:54 -04:00
Nicola Mometto
2ac5ed4fb0 add task-runs to usage analytics (#68288)
* feat: ad v_task_runs

* feat: update v_tasks view

* update permissions/test

* add views

* remove fieldusersettings from export, channels

* add task runs model
2026-01-20 10:39:56 +00:00
Sébastien
1b80d7dc16 Enable editing/creating native questions in the SDK (#68138)
* .

* .

* .

* edit is actually working

* add now works too

* fix

* added e2e test

* doc

* .

* added a wait to see if that helps

* better waits

* .

* addressed comments

* Apply suggestions from code review

Co-authored-by: Alex Yarosh <alexandra@metabase.com>

* test

* test

---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-01-20 08:37:11 +01:00
github-automation-metabase
34266fc636 Update translations 2026-01-20 (#68403)
* Update translation sources 2026-01-20

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-20 06:23:53 +00:00
Alexander Polyankin
e3ced91a43 Make filtering in the deps graph consistent with the task lists (#68373) 2026-01-20 03:36:05 +00:00
Anderson
a37b3fb0ec Implement read-only mode on Snippet detail page (#68268)
* Implement read-only on Snippet detail page

* Add more tests

* Fix mock

* translate string
2026-01-20 00:48:51 +00:00
Romeo Van Snick
1284c201b5 MBQL lib test helpers (#68168)
* Add test helper definition and implement joins

* Add support for fields clause

* Be explicit with types

* Pull out findJoinStrategy helper

* Pull out appenTestQueryStage

* Simplify helpers

* Move helper

* Allow disamiguating column name

* Fix rhs columns

* pull out createTestJoinClause

* Add filters

* Add aggregations

* Add breakouts

* Add expressions

* Add ordering

* Add limiting rows

* Make source optional

* Make provider the first argument

* Expand example in tests

* Automatically pick the base column if no table was specified

* Remove unused sourceMetadata argument where not needed

* Fix join metadata

* Improve types

* Add createNativeQuery and createNativeJsQuery helpers

* Use column groups to disambiguate instead of table name

* Test the results

* Deprecate createQuery

* Replace createQueryWithClauses with createTestQuery

* Add SAMPLE_PROVIDER

* Add helpers to build metadata provider

* Use displayName for groupName

* Remove raw mbql in test and replace it with Lib inspections
2026-01-20 11:04:16 +11:00
Nemanja Glumac
feb0c5b34a Add pre-commit hook to auto-fix unused requires flagged by clj-kondo (#68274)
This introduces a pre-commit hook that automatically removes unused require
statements detected by clj-kondo, preventing CI failures.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 00:10:01 +01:00
bryan
58e4025456 Fix flaky dataset-already-loaded?-test for Redshift (#68292) 2026-01-19 13:44:59 -07:00
bryan
9ceae0061a Fix mage doctor on Linux: use which instead of command -v (#68381)
`command` is a shell builtin that doesn't exist as a standalone binary on
Linux (only macOS has /usr/bin/command as a wrapper). When babashka tries
to execute `command -v git` directly via process/shell, it fails on Linux
because there's no `command` binary to run.

Using `which` instead works on both platforms since it's an actual binary.
2026-01-19 20:04:10 +01:00
metamben
2cb8a32def Add back typo fix removed by merge (#68375) 2026-01-19 20:00:32 +01:00
Edward Paget
59adba6f98 feat: generic oidc provider using auth-identity (#65872)
* feat: add generic OIDC provider infrastructure

Add OSS infrastructure for OIDC-based authentication providers:

- OIDC discovery: automatic endpoint discovery from issuer URL
- Token handling: ID token validation, parsing, and claim extraction
- State management: encrypted state cookies for CSRF protection
- Schema validation: Malli schemas for OIDC configuration and tokens
- Common utilities: shared HTTP and request utilities

This provides a foundation for enterprise SSO integrations that use
OIDC/OAuth2 flows (e.g., Slack Connect, generic OIDC providers).

* fixup! dead code clean up

There was a bunch of speculative code we didn't end up using when this
change from a 'configurable OIDC' to a just support slack course

* fixup! ttls for caches for jwks/discovery

fixup! check for open redirect when creating oidc state

* fixup! use valid-hosts? to check before making jwks/discovery requests

* fixup! don't use hardcoded jwt algo

* fixup! use java-time

* fixup! kondo

* fixup! use system.core not system.settings
2026-01-19 12:04:55 -06:00
Denis Berezin
1da7a523b8 Use proper link in public powered by metabase footer link (#68301)
* Use proper link in public powered by metabase footer link

* Fix tests

* Fix tests
2026-01-19 20:47:41 +03:00
Alexander Polyankin
6165e70718 Fix :view_count not returned for relevant entities in the dependencies graph (#68370) 2026-01-19 17:43:54 +00:00
metamben
1a2f012afe Show sensitive columns in the sandboxing UI (#66757)
* Show sensitive columns in the sandboxing UI

Closes #53378
2026-01-19 16:33:20 +00:00
Brad Anderson
c8b6f74578 UXW-2341 Add Caching tab for metrics in Data Studio (#66513) 2026-01-19 10:51:51 -05:00
metamben
905c5dde99 Report datetime insights even if columns is PK or FK (#67536)
Closes #35281
2026-01-19 15:10:27 +00:00
Alex Yarosh
913e0c9ee8 docs: IAM for RDS (#68349)
* Update IAM authentication details for RDS instances

Clarified the types of RDS instances that support IAM authentication.

* Update docs/databases/connections/aws-rds.md

* Update docs/databases/connections/aws-rds.md
2026-01-19 09:20:26 -05:00
github-automation-metabase
9eb6d7c74d Auto-update documentation for master (#68332)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-19 09:08:06 -05:00
Phoomparin Mano
a27a3d286b Fix flaky assertion for "sdk iframe embedding fires ready event after iframe is loaded" (#68336) 2026-01-19 19:45:38 +07:00
Nicola Mometto
03d26b2a19 fix spelling typo (#68342) 2026-01-19 11:46:08 +00:00
Dan Stone
4fa44b5fc7 Use Soft/Weak references for malli cache entries (#68076) 2026-01-19 10:51:25 +00:00
Nicola Mometto
2e3746de55 Task Run Monitoring (#68116)
* add task_run table and followup migrations

* fix: missing remarks

* feat: task-run model

* wip: logs and run-id in task_history model

* wip: endpoints

* chore: dead code

* simplify

* simplify

* Add log capture factory

* Move log capture to history

* feat: prevent running if nested

* Capture logs during task history

* Tests + fixes for log capture

* Avoid log aliases and kondo the discouraged c.t.logging ns

* style

* fix

* feat: wrap with with-task-run

* Add `:ts` timestamps to captured log entries

* Skip DEBUG/TRACE

* Add basic log truncation

* Test log truncation

* Fix sync tests

* Add :model/TaskRun resolution.clj entry

* GDGT-1497 add TaskRun UI part

* feat: hydrate-task-counts

* fix: nil protect limit/offset

* style

* fix: move with-task-run to core ns

* fix: ignore TaskRun from copy test

* fix: no need for name

* fix: typo

* wip

* fix: build-run-where-clause

* exclude task run from entity_id/deser

* feat: add with-run-id helpers

* chore: make complete-task-run idempotent

* feat: export more utils

* fix: support async notification/alerts

* kondo

* fix: test

* support legacy cards

* make sure we complete-task-run in send- sync

* add index to fk

* fix: current-run-id

* fix: move around

* add tests

* fix: needs keyword

* hook up to test endpoints too

* preserver ordering

* handle non hydrated

* add integration tests

* depend on no-op nested behavior, add comment

* fix

* fix: coerce

* GDGT-1497 add TaskRun UI part

* conform to logs format

* chore: add process_uuid

* GDGT-1497 add TaskRun UI part

* GDGT-1497 add TaskRun UI part

* feat: track uuid/updated_at in task run for orphan detection

* add unknown status

* feat: store updated_at/process on insert

* chore: use abandoned

* feat: orphan task

* make not nullable

* chore: add abandoned to FE

* fix

* feat: also abandon if exceeds max duration

* add integration test

* appease prettier

* GDGT-1497 add TaskRun UI part

* GDGT-1497 addressing PR comments

* GDGT-1497 fix url

* GDGT-1497 fix db name and db engine rendering

* GDGT-1497 extract TaskStatusBadge and TaskRunStatusBadge

* GDGT-1497 clean up

* fix typo

* feat: onDelete set null instead of cascade

* GDGT-1497 fix e2e tetst

* Update src/metabase/task_history/models/task_history.clj

Co-authored-by: Dan Stone <wotbrew@gmail.com>

* GDGT-1497 add new e2e tests

* GDGT-1497 fix eslint rules disabling in new e2e tests

* GDGT-1497 addressing PR comments

* fix out of order timestamps

* fix: missed two

* GDGT-1497 addressing PR comments

* GDGT-1497 fix ts issues

* GDGT-1497 fix flakey test

---------

Co-authored-by: Dan Stone <wotbrew@gmail.com>
Co-authored-by: Egor Grushin <egor@metabase.com>
2026-01-19 09:58:36 +00:00
Romeo Van Snick
46b0aa85a2 Fix broken loki test (#68334)
Update Loki Snapshots

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-19 09:48:08 +00:00
Gabriel Moreno
bb66df77e1 Add library stats to anonymous daily stats ping (#68071)
* feat: add library stats to anonymous daily stats ping

* test: add unit spec for library stats

* test: use the `mt/with-temp` macro
2026-01-16 18:31:25 -04:00
Eric Normand
293d47d3e8 Transforms job runs keep trying other transforms if one fails. (#68141)
Previously, when running a transform job (e.g., daily), it would fail if a single transform in the run failed. This PR makes it so that the job continues to run transforms that don't depend on any failed transform. As previously, if any transform in the run fails, the job is marked as failed.
2026-01-16 22:30:31 +00:00
Nathan Voxland
d6da219a70 Fixes from code review and getting back to project 2026-01-16 16:28:37 -06:00
Gabriel Moreno
3f1ff1ba60 Library empty state: expand Data, Metrics and SQL snippets (#68241)
* feat: add empty states for library items

* test: add e2e specs

* refactor: cleanup library section layout

* test: compact e2e specs into 2 major flows
2026-01-16 18:26:46 -04:00
Timothy S. Dean
e694056f0f Fix coercion for UNIX timestamp fields via implicit joins (#68164)
Addresses #67704.

When a UNIX timestamp is accessed through an implicit join, the coercion to DateTime wasn't being applied. The `allow-casting?` check requires `pos-int?` on `::source-table` to apply coercion. For implicit joins, `::source-table` is set to a string, so it was being skipped.

Fix: in `add-alias-info/add-source-to-field-ref`, wet the flag `:qp/allow-coercion-for-columns-without-integer-qp.add.source-table`. I cribbed this approach from the SparkSQL driver, when it has to rewrite a numeric ID with a string.
2026-01-16 15:26:26 -07:00
Gabriel Moreno
de171c2092 Make Python and SQL editing in Data Studio consistent (#68212)
* feat: configure initial read-only mode for python transforms

* refactor: hide UI elements in readonly mode

* refactor: move database selector to the topbar

* style: add in/out animations for bottom panel

* refactor: move common library controls to the topbar

* test: add unit specs for python transform editor sections

* test: add e2e spec

* fix: show correct run query button state after edits

* refactor: general cleanup & test trimming

* refactor: remove source controls

* refactor: trim down test mocks

* fix: pass missing `editable` flag to transform editor

* fix: types

* fix: e2e data source selector

* refactor: use `isEditMode` instead of `readOnly`
2026-01-16 18:12:20 -04:00
Nathan Voxland
65426fe653 Merge remote-tracking branch 'refs/remotes/origin/master' into persistent-queue
# Conflicts:
#	resources/migrations/059_update_migrations.yaml
2026-01-16 16:11:19 -06:00
github-automation-metabase
fd2bf97c1f Auto-update documentation for master (#68219)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-16 16:44:55 -05:00
Denis Berezin
0bba5e8742 UXW-46 Safari smart scalar truncation (#68248)
* UXW-46 refactor solution

* Update Loki Snapshots

* Fix typecheck

* Fix e2e

* Refactor to simpler solution

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-17 00:43:41 +03:00
Nick Fitzpatrick
3302e9cafd Gdgt 912 update scalar second tab and configuration to support color (#67877)
* adding segment editor to scalar

* temp

* adding tooltip

* pretend i'm a clojure dev, disable tooltip when there are no segments

* adding unit test and story

* loki tests

* silly me

* I am a clojure god

* adjustments

* adding docstring, adjusting loki test

* combining scalar loki tests

* CardSegment -> ScalarSegment

* BE update, filter unvalid segments
2026-01-16 16:37:41 -04:00
Denis Berezin
18c485d06c Fix missing labels for bar chart (#68299)
* Fix missing label for cartesian

* Add e2e tests

* Add comment

* Update Loki Snapshots

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-16 22:54:53 +03:00
Aleksandr Lesnenko
68d40f2770 Ask for loki stress testing (#68302)
update docs, pr template
2026-01-16 14:51:09 -05:00
Nemanja Glumac
b92393b9f0 Enable codespell GitHub action for src folder (#68213) 2026-01-16 13:37:22 -06:00
Egor Grushin
83ca220730 GDGT-1419 warn when incremental edits break checkpoint auto selection (#67933) 2026-01-16 17:49:14 +00:00
Thomas Schmidt
ba7c5d1fc7 Require free text for ui-bug and other feedback types (#68234)
* Require free text for ui-bug and other feedback types

Add Yup validation to MetabotFeedbackModal that requires free text feedback when issue type is ui-bug or other. Issue types requiring free text are maintained in a constant array for easy extension.

* Address PR feedback: improve type safety and UX in feedback modal

- Replace 'as any' with proper TypeScript type assertion
- Fix type inconsistency between schema and initial value for issue_type
- Add dynamic label showing '(required)' when ui-bug or other is selected

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* pr feedback

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Sloan Sparger <sloansparger@gmail.com>
2026-01-16 11:34:12 -06:00
Nemanja Glumac
2cf11310a8 Fix untranslated string in an alert modal (#68287)
Co-authored-by: Joseph Adams <danielowenderefaka@gmail.com>
2026-01-16 17:53:24 +01:00
Riley Thompson
06d4da18c3 Surface analysis errors with upstream dependencies (#68092)
* initial work

* fix test

* fix another test

* source entity malli schema

* clean up and add test

* add tests

* clean up

* fix tests

* drop finding_details column

* fix analysis version

* Update enterprise/backend/src/metabase_enterprise/dependencies/models/analysis_finding.clj

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>

* use transaction

* use node-errors refactor suggestion

* use maybe-resolve-join

* add schemas

* add comment

---------

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>
2026-01-16 15:08:44 +00:00
John Swanson
44e118b5e3 Manage table metadata allows syncing table (#67868)
This is the permission we're correctly checking with the below
`api/check-403` but by using `warehouses/get-database` (which, btw, has
the MOST confusing possible arguments I've ever seen) we were throwing a
403 if we didn't have read access to the whole database (which
checks *create-queries* perms on the entire database).

We still need to exclude mirror databases. In the medium term there
might be a better way to do this - maybe we could somehow have two
different models, so `(t2/select :model/Database)` would always exclude
mirror databases, while `(t2/select
:model/DatabaseIncludingMirrorDatabase)` would return them? I dunno.
2026-01-16 06:13:15 -08:00
Gabriel Moreno
3a490774cc Fix the Glossary deduplication UX (#68243)
* feat: prevent duplicate glossary terms from being added

* test: add unit spec
2026-01-16 09:55:25 -04:00
Timofey Kachalov
d5ad9d6142 fix(embed-js): adjust experience reset logic to avoid unexpected experience resets (#68273) 2026-01-16 17:09:53 +04:00
William
eacff63768 Disable native sql validation (#68148)
Native sql validation is a bit too unreliable for general deployment at the moment, so we are disabling it for check_* endpoints and the broken entities list unless/until we can make it more reliable.

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-01-16 11:28:04 +00:00
Timofey Kachalov
6cea29bace Fix wrong BG value in TableActionInputSearchableSelect (#68275) 2026-01-16 15:21:35 +04:00
Dan Stone
e3d6d76bf8 Hide 0 estimate row counts to avoid confusion (#68190)
Treats 0 n_live_tup as NULL, due to confusion reported when auto analyze
thresholds have not been met on a table.

To justify:
- You have a non-zero estimate (No change)
- A zero estimate but actually have rows (We now hide the estimate)
- A zero estimate and actually have zero rows (We now hide the estimate,
unfortunately)

This behaviour is considered on balance preferable to the behaviour now
where users will likely be confused, even thought we explicitly label
the field 'estimated'.

Other options considered that we might explore in the future:
- Forcing ANALYZE, e.g. on sync
- Bounded/LIMIT count
- Some policy based on last analyze timestamps
- Better tooltips or explaination on frontend

We should revisit in the future once we have a better idea for how
estimates should work across drivers (as its only postgres for now).
2026-01-16 09:03:21 +00:00
Timothy S. Dean
37243f5469 Delete invalid source-card-ids on native SQL questions (#68100)
When a user creates a question based on a model, `source_card_id` was set to the model's ID. If that question was later converted to native SQL, `source_card_id` wouldn't get cleared. This means that deleting the model would cause the question to be deleted even though they no longer have any relationship to one another.

The code fix won't help anyone whose data is already incorrect, so this adds a migration to correct the inconsistent data. I added an assertion to the t2 hook to catch this at dev time in the future. And ultimately, the delete cascade seems overkill, so there's a migration to replace that with SET NULL instead.
2026-01-15 16:19:13 -07:00
bryan
ad60b57c4a Fake sync for Redshift tests (branch-conditional, refactored) (#67603) 2026-01-15 15:53:45 -07:00
Anderson
fa924880ad Implement read-only on Library & Data Structure pages (#68209)
* Implement read-only on Library page

* Add some gorgeous unit tests

* Make segment and measures read-only / Add tests

* Apply read-only logic to measure list and segment list pages
2026-01-15 19:50:51 -03:00
Romeo Van Snick
bace1d68c5 Flake fix: allow clicking gridcells while animating (#68218)
Allow clicking while animating
2026-01-16 09:44:15 +11:00
Maksym Yakubych
0523cf2397 fix: dropdown menu in create/edit record on database table (#67807) 2026-01-15 17:51:15 -04:00
Alexander Polyankin
c75465cd07 FE fixes for upstream dependencies (#68254) 2026-01-15 16:44:08 -05:00
kevinkelleher12
a76e880fdd Fix filters not closing properly on native SQL questions (#68216) 2026-01-15 16:06:26 -05:00
Alexander Polyankin
032d1e9ea5 Add server-side sorting to broken & unreferenced items pages (#68221) 2026-01-15 19:59:14 +00:00
Oleksandr Yakushev
b2840f32f9 Replace amalloy/ring-buffer dependency with already included CircularFifoQueue (#66007) 2026-01-15 20:34:29 +02:00
Timofey Kachalov
499eacf3d1 Fix EE Starter Edition Embedding Admin page visuals (#68226) 2026-01-15 21:27:33 +04:00
Denis Berezin
23d9096d0b UXW-136 Fix issue with bar viz on filtered column (#67573)
* UXW-136 Fix issue with bar viz on filtered column

* Review fixes

* Refactor solution

* Review fix
2026-01-15 17:17:07 +00:00
Dan Stone
594cd0cc89 Remove ^:parallel meta for tests that search + hold locks (#68240)
A recent change to search permissions queries in [#67055](https://github.com/metabase/metabase/pull/67055) will cause H2 to use SYS locks during search operations. This is because H2 uses temporary tables to implement CTE's, and their creation/dropping requires global locks.

This commit removes some ^:parallel meta in an attempt to avoid test
flakes due to lock timeout.

This change is a bit speculative:

- It is not 100% confirmed that parallel tests are the only problem (e.g. some background task might also hold a lock)
- The tests changed are based on a cursory scan for search tests that
  hold transactions (mt/with-temp). There may be other tests.

The impact of the CTE lock behaviour in production searches is likely
minimal because:

a. Search queries will typically run in auto commit sessions and so lock
lifetime will be short
b. concurrent multi-user deployments are most likely not on H2.

Should keep an eye on both tests and any reports in production of lock
timeout errors / slow searches when using H2.
2026-01-15 17:05:14 +00:00
da
f3c0be5fc1 Log error instead of warning if a subscription is not sent through the channel rather than a warning (#68214)
* Why is it a warning when it should be an error?

* Fix error logging format in notification worker

* Improve error logging in notification send process

Fix silly mistakes that I do when I'm sleepy
2026-01-15 13:20:40 -03:00
Timofey Kachalov
950b555558 feat(sdk, embed-js): Add Content Translations for SDK InteractiveQuestion new query Editor (#68063) 2026-01-15 20:13:21 +04:00
Jeff Bruemmer
2e65eac90e docs- remove sample app (#68235)
remove sample app
2026-01-15 14:59:24 +00:00
Timofey Kachalov
c73ccb8be7 Cleanup additional space to properly build Sample Apps (#68229) 2026-01-15 17:31:59 +04:00
William
7976ad4f47 Refresh child card result metadata on card edit (#68043)
When a card is updated, look for all mbql child cards and recalculate their result metadata.  With models, calculate
what their "correct" result metadata is pre-update, use that to calculate user overrides, and then reapply those
overrides when computing the new result metadata.

This should fix a variety of bugs around users updating a model and then not seeing those change downstream.
2026-01-15 09:41:36 +00:00
Thomas Schmidt
825719067a Improve Metabot input and message scrolling UX (#68117)
- Add max-height and vertical scrolling to input area
- Fix newline preservation in multi-line messages
- Add horizontal scrolling for wide code blocks in messages
- Style code blocks with proper background, border, and custom scrollbar
- Reduce code font size to 0.6875rem for better proportion
- Increase user message bubble width to 90%
- Add inline code styling with background and border
2026-01-15 08:43:34 +00:00
Anderson
95af300c15 Disable git pull button when there are no changes to pull (#67968)
* Add /has-remote-changes endpoint to remote-sync API

Adds a new endpoint GET /api/ee/remote-sync/has-remote-changes that checks
if there are changes on the remote (Git) repository that can be pulled.

Response format:
{
  "has_changes": true,
  "remote_version": "abc123...",
  "local_version": "789xyz...",
  "cached": false
}

* Disable git pull button when there are no changes to pull

* Fix unit test

* Fix e2e

* Adjust conflict modal 'push' option to always force

* Fix conflict resolution options when switching branches

* Fix modal title not wrapping properly

* Fix long long modal title e2e issue

---------

Co-authored-by: Edward Paget <ed.paget@gmail.com>
2026-01-14 23:38:57 -03:00
Nemanja Glumac
d2f3648298 Remove embedding dev-related folders from Snyk (#68207) 2026-01-14 22:12:35 +01:00
Edward Paget
60093c461b Add /has-remote-changes endpoint to remote-sync API (#67924)
* Add /has-remote-changes endpoint to remote-sync API

Adds a new endpoint GET /api/ee/remote-sync/has-remote-changes that checks
if there are changes on the remote (Git) repository that can be pulled.

Response format:
{
  "has_changes": true,
  "remote_version": "abc123...",
  "local_version": "789xyz...",
  "cached": false
}

* Update api_test.clj
2026-01-14 14:25:41 -06:00
da
aab9fc000a Increase verbosity in the caching middleware (#68121)
* Increase verbosity in the caching middleware

* Fix linter

* Make it simpler

* Broke so many tests

* Make the linter happy

* Fix tests (going back to old implementation)
2026-01-14 17:22:58 -03:00
Timofey Kachalov
28baf73201 Cache Main App/Embed JS fonts (#68120) 2026-01-14 23:14:22 +04:00
Nathan Voxland
6403d80fea Merge branch 'master' into persistent-queue 2026-01-14 11:11:53 -06:00
Timofey Kachalov
2a70fd1794 fix(embed-js): Fix EmbedJS/SDK dashboard styles to properly display the EmbedJS branding footer (#68090) 2026-01-14 20:06:35 +04:00
github-actions[bot]
05105be4c7 Fix: Add Error state for incorrect CSV/TSV file upload type (#67150)
* Fix: Add Error state for incorrect CSV/TSV file upload type

Fixes #40589

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* make the AI code a bit better

---------

Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-01-14 15:53:57 +00:00
github-actions[bot]
c0663854c7 Fix: Having : as a special character in the DB name breaks the UI for Clickhouse (#68013) 2026-01-14 10:51:18 -05:00
Alexander Polyankin
fe4d26ab63 Fixes computing columns for Question -> Question -> Model on the FE (#68140) 2026-01-14 09:46:11 -05:00
Edward Paget
30cd48cc7c feat: add table/field/segment support to remote-sync (#67327)
Fully support remote-sync for data studio and make it easier to extend support for remote-sync to other models in the future.

    Supports serializing tables with their fields and segments via remote sync if they are published to a remote-synced collection.
    Supports dirty state tracking of tables, fields, and segments.
    Refetches dirty state when tables, fields, and segments are created/updated/deleted in the data studio
    Make sure the data studio still displays content when remote-sync is in read-only mode
    enforce that tables, fields, and segments published to remote-synced collections are not editable when remote-sync is in read-only mode.
    Deletes, tables, fields, and segments from the remote-sync repo when they are removed or archived.

This also creates two small abstractions to make it easier to add new models (like measures) to remote-sync when they are ready. The remote-sync.events models adds a defmodel-change-handler macro that setups handlers for -create, -update, -delete, events models can publish that the dirty state tracking will follow.

Right now the UI does not change when the data studio is in read-only mode, but all create/edit operations correctly return 403 if you try to modify things. I have a follow up branch to support disabling UI elements.

* feat: add dirty tracking for model changes

* feat: add table, field, segement to dirty state query

* feat: extract fields with tables and segments

when exporting a collection with a table we want to include its children
like fields and segments

* feat: allow importing/deleting tables

and segments and fields

* feat: add dirty tracking for field/segment

* feat: show path in git sync controls

* fix: skip archived segments in table descendants

* fix: view library when in read-only remote-sync

Allows users to still see library folder they can't edit when that
condition is caused by the library being remote-sync enabled and the
instance being in remote-sync mode.

* feat: use remote-sync status in table edit perms

* fix: don't use include_editable_data_model param

...in data studio so these will still load when remote sync is read-only.

* fix: always show dirty library state on removed

We can't track what collections a table was removed from so we just want
to show the library as dirty if any item has a 'removed' dirty state.

* chore: update modules config

* chore: fix kondos

* fix: only publish table update events on ee

otherwise a handler doesn't exist which causes them to throw

* fixup! whitespace

* refactor: make the table changes rendering simpler

* fixup! missing when

* fixup! tests shouldn't mock modules

* fix: make dirty tracking work with new implementation

* refactor: make the hydration step in events cleaner

* fix: make sure dirty returns lowercase

* fix: delete segments correctly

* fixup! remove extra module

* fixup! correct migration order

* fixup! FE lints and typecheck

* fixup! remove correct extraneous module

* Update enterprise/frontend/src/metabase-enterprise/remote_sync/components/ChangesLists/EntityLink.tsx

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>

* fixup! PR feedback and tsc

* fixup! segment failing to redirect

* fixup! better fix for navigate after save

---------

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
2026-01-14 08:35:16 -06:00
Jeff Bruemmer
b3f62b6b6d note on slack notifications (#68153)
* note on slack notifications

* fix link
2026-01-14 09:23:07 -05:00
github-automation-metabase
50270bc649 Auto-update documentation for master (#68167)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-14 09:09:04 -05:00
Romeo Van Snick
b595e58985 Fix a broken model e2e test (#67499) 2026-01-14 15:07:53 +01:00
John Swanson
08b309f4c8 Fix perms checks for unarchiving collections (#67729)
* Fix perms checks for unarchiving collections

* use `can_restore` as single source of truth
2026-01-14 05:10:29 -08:00
John Swanson
db6808c754 Nicer error msg when trying to pull tenant colls (#67948)
Previously if you tried to pull from a remote sync repository that
contained tenant collections you would get an incomprehensible error
that didn't explain what was wrong.

[EMB-1104: Update error message when trying to pull Tenant collections with Tenants turned off](https://linear.app/metabase/issue/EMB-1104/update-error-message-when-trying-to-pull-tenant-collections-with)
2026-01-14 05:08:42 -08:00
John Swanson
ce252a2a8b include API keys when copying DBs (#67998)
[UXW-2690: Instance restored from a H2 snapshot is missing API keys](https://linear.app/metabase/issue/UXW-2690/instance-restored-from-a-h2-snapshot-is-missing-api-keys)
2026-01-14 05:08:27 -08:00
John Swanson
701b90bb9c Increase the unreturned cxn timeout for appdb (#67571)
For the data warehouses we can safely set a fixed
unreturnedConnectionTimeout to a fairly low number (5 minute default)
because we also have a default maximum query length for data warehouses,
which can't be exceeded anywhere.

For the application DB though, this isn't safe, as operations against it
can legitimately hold connections for extended periods - for example,
dump-to-h2 on large databases streams data for as long as it takes to
copy all rows.

Bumping this to 1 hour by default (configurable via
`MB_APPLICATION_DB_UNRETURNED_CONNECTION_TIMEOUT`).
2026-01-14 05:08:10 -08:00
John Swanson
16c291f753 Add support for transforms to collection items (#67832)
* add support for transforms

* tests and hide from non-superusers
2026-01-14 05:07:54 -08:00
dpsutton
a469da0955 simpler tests? you decide (#68144)
* simpler tests? you decide

* ignore discouraged var. just tests. don't need api docs

* avec-server -> with-server

originally there was another `with-server` and i didn't want to clobber
it until i was ready

* bit of cleanup

* cljfmt

* bit of linter appeasement
2026-01-13 16:39:38 -06:00
Nemanja Glumac
9a6393ff4a Enable codespell for dev folder (#68124) 2026-01-13 15:23:18 -07:00
Jeff Bruemmer
46bef2348b docs - skip txt (#68154)
skip txt
2026-01-13 17:10:42 -05:00
John Swanson
0266970fff Admins see personal collections for tenant users (#67949)
* Admins see personal collections for tenant users

[EMB-1110: As an Admin, I want to be able to see personal collections of external users](https://linear.app/metabase/issue/EMB-1110/as-an-admin-i-want-to-be-able-to-see-personal-collections-of-external)

This was already implemented on the BE. Claude helped with the FE but I
think it seems reasonable.

* CR resp

* Remove pagination
2026-01-13 13:17:40 -08:00
Riley Thompson
88ec74f7b3 Upgrade clickhouse to 0.9.5 (#67297) 2026-01-13 15:48:20 -05:00
bryan
b07c00001d Fix nested & misused is in tests found by new kondo version (#67939) 2026-01-13 13:08:40 -07:00
Gabriel Moreno
11e96da48b UXW-2666 Row chart tooltip doesn't reflect column rename (#68137)
* fix: prefer title_text over display_name

* test: add dimension key unit spec

* refactor: rename to `columnTitle`
2026-01-13 18:11:57 +00:00
Thomas Schmidt
5ab27ac0fb Support measures and segments for Metabot (#67368)
* Support measures and metrics for Metabot

* Add segment support to metric querying

* Minor clojure tweaks for metabot measures and segments poc (#67425)

* Handle measures and segments like metrics in table-details and card-details

Move these into the existing m/assoc-some and handle them in the same way as metrics

* Remove query->output-format

This was just a wrapper around lib/->pMBQL, but all these queries are already MBQL5 queries

* Metabot measures and segments cleanup and tests (#67488)

* some refactor

* draft some happy path tests

* use lib for creating measure and segment clauses

* fix tests

* fix some filter tests to use mbql5

* update more tests

* fix more tests

* fix model query syntax

* lint

* remove normalize call again

* add back normalize

* minor test cleanup

* address comments

* tweak another test

* add a query= helper that strips uuids, update a number of tests to use it

* add basic error handing for bad ids

* Minor cleanup

* address mike's comment

---------

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
Co-authored-by: Noah Moss <noahbmoss@gmail.com>
2026-01-13 12:50:17 -05:00
Alexander Polyankin
7cd7ef457a Broken & unreferenced entities - add pagination, expose tables (#68110) 2026-01-13 16:42:14 +00:00
Edward Paget
79f43e1259 fix: don't unset remote-sync settings on api req (#67605)
* fix: don't unset remote-sync settings on api req

...if request is partial. Fixes an issue where the token could be unset
when switching between read-write and read-only modes.

* add debugging

* remove debugging

* fixup! handle extra collection

* fixup! update syntax
2026-01-13 09:46:14 -06:00
Jakub Chodorowicz
739a915d5d Uxw 2596 color range on table crashes it if values span a large scale (#68022) 2026-01-13 16:39:04 +01:00
Anderson
5c6c075103 Improve design of no-owner state in data structure side panel (#67772)
* Improve design of no-owner state in data structure side panel

* fix e2e test
2026-01-13 12:12:03 -03:00
Denis Berezin
2d76c2fb74 Fix public powered by metabase footer link (#68069)
* Fix public powered by metabase footer link

* Fix tests
2026-01-13 17:43:47 +03:00
Jakub Chodorowicz
63be293945 Prg 160 add ssl grouping config (#67682)
Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
2026-01-13 15:09:30 +01:00
Nemanja Glumac
221b76041d Enable codespell GH action for frontend (#68073) 2026-01-13 13:05:19 +00:00
Nemanja Glumac
8d4837c6b0 Remove deprecated moveDnDKitElement helper (#67604)
Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>
2026-01-13 13:49:49 +01:00
github-automation-metabase
7879a97840 [chore] Update llms.txt for master (#68113)
Update llms.txt and llms-full.txt (master)

Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.

🤖 Generated automatically by llms-txt-generate workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-13 09:49:53 +00:00
github-automation-metabase
4d820ce589 Auto-update documentation for master (#68105)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-12 20:35:29 -05:00
Nathan Voxland
cdcaaf5f33 If the entity id is unknown when calling the export API, throw an error (#68040) 2026-01-12 17:07:26 -06:00
bryan
a2e9d66d7a Disable regex lookaheads/lookbehinds for Snowflake driver (#68084) 2026-01-12 14:57:04 -07:00
github-actions[bot]
04d68a6a41 UXW-46 In Safari Scalar is truncated like a string rather than a number (#67207)
* Fix: In Safari, Reducing the Tile Size of a Number viz Might Result in the Number Being truncated like a String Rather than Rounded

Fixes #51082

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* UXW-46 refactor claude solution, implement proper fix

* Update Loki Snapshots

* Fix e2e tests

---------

Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-13 00:10:24 +03:00
Denis Berezin
ad87e0366a UXW-64 Fix table cell formatting for temporal breakout by week (#67477)
* UXW-64 Fix table cell formatting for temporal breakout by week

* Review fixes
2026-01-13 00:09:17 +03:00
Edward Paget
90ba3e39e7 feat: split can-read from can-query in data model (#67815)
* feat: split can-read from can-query in data model

Adds a new kind of permission type `can-query` that describes when a
user is allowed to query the data model vs `can-read` which encompasses
when a user can see the metadata of a query. This makes api calls to
read table metadata more straightforward and the eventual integration
with remote sync easier.

* feat: update api to use can-edit/can-query params

* fixup! allow can-write-metadata queries

* fixup! field test

* fixup! whitespace

* fixup! returning empty lists instead of 403

* fixup! schema response

* fixup! enforce query permissions where necessary

* fixup! add last tests

* fixup! can query filter before saved questions
2026-01-12 14:46:40 -06:00
Nathan Voxland
bbcba1500c Added queue_message table back 2026-01-12 14:29:48 -06:00
Nathan Voxland
fcf4dbb6e8 Merge branch 'master' into persistent-queue
# Conflicts:
#	.clj-kondo/config/modules/config.edn
#	resources/migrations/056_update_migrations.yaml
2026-01-12 14:29:04 -06:00
Cam Saul
ee9ba65762 Introduce module :friends (#67292) 2026-01-12 11:54:04 -08:00
Cam Saul
469c2f4681 Minor cleanup: fix function with side effects name (#68044) 2026-01-12 18:29:26 +00:00
Maksym Yakubych
696d8eec73 fix: text selection inside card embed when interacting with card embeds (#67761) 2026-01-12 13:25:34 -05:00
kevinkelleher12
fbe2dd23a4 Fix funnel viz to handle increasing data (#68031) 2026-01-12 18:02:03 +00:00
Anderson
85fe26063c Fix data studio missing some hover states (#67891)
* use ActionIcon for data studio toggle icon

* Use ActionIcon on snippet tree row ellipsis menu

* Change link colors in breadcrumbs on hover

* Use ActionIcon for tree expand icon

* Update hover state on transforms runs filters

* Fix data studio nav collapsed logo hover

* Match hover state on snippets collection and snippets folders

* Fix ts
2026-01-12 14:24:53 -03:00
Alex Yarosh
afdd39c531 docs: Update link to Metabase pricing page (#68067)
Update link to Metabase pricing page
2026-01-12 14:35:23 +00:00
github-automation-metabase
fb22fed921 Auto-update documentation for master (#68052)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-12 09:34:12 -05:00
Edward Paget
07c5e47251 fix: remote-sync origin url errors (#67594)
* fix: remote-sync origin url errors

Fixes issues where the tmp directory for the remote-sync repo can get
into a bad state where it doesn't have an origin URL. This calls a
function that explicitly sets our desired origin URL and updates all
calls to use the more specific :remote-url keyword rather than
inconsistently using :url vs :remote-url.

* Update git_test.clj
2026-01-12 08:23:50 -06:00
metamben
fd9a13e05e Measures cleanup (#67960)
* Extract cycle detection algo and fix available-measures
* Rremove duplicated code.
* Add more serialization tests
* Fix CLJS
* Remove MBQL4 support for measures at the  model level
2026-01-12 17:09:35 +03:00
Phoomparin Mano
a46764dd85 Add virtualized grid to collection list view for tenants (#67958)
Co-authored-by: Sébastien <sebastien@metabase.com>
2026-01-12 13:42:20 +00:00
Phoomparin Mano
a4e306f9cf Fix issues with the llms.txt generation workflow (#68019) 2026-01-12 17:07:07 +07:00
Phoomparin Mano
4ec8c0cb0e fix(sdk): fix crashes on React 19 due to findDOMNode on Gauge and Modal (#67953) 2026-01-12 16:56:43 +07:00
Alexander Polyankin
bff5dfb5eb Fixes (#68046) 2026-01-10 03:31:22 +00:00
Aleksandr Lesnenko
0deffd6231 add loki stress test workflow (#68042) 2026-01-09 20:36:22 -05:00
Aleksandr Lesnenko
9311117086 tweak tree table column widths (#68035)
* tweak tree table column widths

* tweak widths

* specs
2026-01-09 23:11:23 +00:00
Alex Yarosh
9a37785bc3 Fix sentence in JWT Identity Provider URI description (#68038) 2026-01-09 17:44:33 -05:00
Alexander Polyankin
3b52306116 Add a filter for personal collections; preserve filters in the URL, drop the broken dependencies page for now (#68008)
* wip

* wip

* wip

* wip

* wip

* Filters

* wip

* tests

* Fixes

* wip

* Add e2e test

* wip

* comment

* wip initial personal coll filter

* allow deleting personal collections

* used by

* whitespace

* lint

---------

Co-authored-by: Riley Thompson <rileythompson99@gmail.com>
2026-01-09 17:33:18 -05:00
Edward Paget
7a753622e0 fix: make sure we don't sync unchanged collections (#67795)
* fix: make sure we don't sync unchanged collections

* fixup! bad test
2026-01-09 15:55:35 -06:00
Edward Paget
09860c0032 fix: limit can_run_adhoc_query hydration (#68028)
We can't hydrate unbounded collections of cards with the
can_run_adhoc_query hydration since it linearly adds db queries to the
request. Users with > 10000k can have severe CPU/memory issues
processing this.
2026-01-09 15:55:06 -06:00
Egor Grushin
48e3b5c190 QUE-2687 remove automatic selection of the first option in TemporalUnitDropdown. (#67598) 2026-01-09 20:59:29 +00:00
Ryan Laurie
08421d9ec1 remove broken overlays demo (#67995) 2026-01-09 20:26:08 +00:00
Jeff Bruemmer
1c9de41832 docs - fix translation docs (#68011)
* fix translation docs

* comment

* sdk

* data

* cleanup
2026-01-09 20:03:15 +00:00
Nemanja Glumac
4497b15aed Enable codespell for modules/drivers (#68010) 2026-01-09 20:58:06 +01:00
Abed Habli
7a8b15e271 Docs: AI exploration (#67859)
* AI exploration section

* Optimized 2 images, saved 221.4 KB (51.0% smaller)

* fix the heading link

* Update docs/ai/metabot.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/ai/settings.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* few edits

* typo

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-01-09 20:54:55 +01:00
Nemanja Glumac
75476f4ae1 Fix frontend typos (#68003) 2026-01-09 20:41:58 +01:00
Robert Kosara
4e60b2efeb Mention search in data picker docs (#67930)
* Replace data picker image, add a line about search

* Optimized 1 images, saved -360 bytes (-1.1% smaller)

* Fix screenshot and description to talk about v58

* Incorporate bot suggestion

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-09 10:41:05 -08:00
Alex Yarosh
3315a9a65a plan callouts (#68014) 2026-01-09 13:33:29 -05:00
Alex Yarosh
d20f6f9f11 docs: minor edits to tenants (#67961)
* Fix heading level for multi-tenant strategy section

* Correct 'Admin setting' to 'Admin settings'

Updated references from 'Admin setting' to 'Admin settings' for consistency throughout the document.

* more edits

* typos
2026-01-09 13:32:51 -05:00
Riley Thompson
686de1c06e Exclude archived items from unreferenced and broken items endpoints (#67950) 2026-01-09 13:08:25 -05:00
Nicolò Pretto
7b6b37264a docs(sdk): remove links to package changelog (#67997) 2026-01-09 18:37:36 +01:00
Nick Fitzpatrick
20ec35314f Typesafe c and bg props (#67899)
* most of the way there

* happy types, simpler themeColor function

* PR Feedback

* make editor buttons slightly less offensive

* final adjustments
2026-01-09 13:31:22 -04:00
Maksym Yakubych
c7f4935d58 fix: ellipsis breadcrumb shows gray background in Dark Mode (#67805)
* fix: ellipsis breadcrumb shows gray background in Dark Mode

* refactor: use `metabase/ui` in `CollectionBreadcrumbs`
2026-01-09 16:55:35 +00:00
Nemanja Glumac
80b6060ab7 Enable codespell for the enterprise folder (#67979) 2026-01-09 17:55:26 +01:00
Timofey Kachalov
b374706a41 feat(embed-js): Change guest embeds disabled tooltip to display a link to admin settings (#67925) 2026-01-09 20:29:38 +04:00
github-automation-metabase
a131b9c921 Update llms.txt and llms-full.txt (master) (#67993)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-09 16:00:20 +00:00
Nicolò Pretto
d4486c9dff fix: make dashboard header use container queries to respond to metabot (#67376)
* fix: make dashboard header use container query

* use named container everywhere

* fix syntax

* rename and extract to other class
2026-01-09 16:59:33 +01:00
Sébastien
ad5cc2877d Allow passing arrays of string as sqlInitialParameters in InteractiveQuestion (#67282)
* Allow passing arrays of string as sqlInitialParameters in InteractiveQuestion

* nit

* better assertion

* pass all initial sql params as is
2026-01-09 16:50:19 +01:00
Jeff Bruemmer
88647269a0 docs - embedding browser options (#67957)
* browser params

* array options
2026-01-09 10:08:14 -05:00
Anderson
f0ab6a222c Show border on segment name editable content in new segment page header (#67946)
* Use PaneHeaderInput on NewSegmentHeader

* Apply segment name on content change
2026-01-09 12:01:39 -03:00
Nicola Mometto
cc9f7e63ad submit transform metering data to metering endpoint (#67902) 2026-01-09 14:36:52 +00:00
Nemanja Glumac
3798862761 chore: Fix safe typos in enterprise/ folder (#67912) 2026-01-09 15:05:04 +01:00
Nemanja Glumac
3fbd0ff00d Increase the viewport width for a flaky "data studio" e2e tests (#67901) 2026-01-09 16:55:20 +03:00
Nicola Mometto
9f30405075 Fix serialization in the presence of xray of usage analytics (#67848)
* feat: separate analytics vs non analytics escapes

* update callsite

* fix: descendant-ids requires coll models

* add test

* fix: nil safe
2026-01-09 09:43:16 +00:00
Romeo Van Snick
363baef1d9 Add defensive toString to column name (#67893) 2026-01-09 14:10:36 +11:00
github-automation-metabase
6cdb558f0e Update generated docs (master) (#67966)
Co-authored-by: github-actions <github-actions@github.com>
2026-01-08 20:40:59 -05:00
Aleksandr Lesnenko
13ec0f6fc8 fix tasks table (#67964) 2026-01-09 01:34:50 +00:00
Nick Fitzpatrick
a6b5cb7371 updating ClauseStep type, fixing segment and measure editors (#67956) 2026-01-08 20:53:19 -04:00
Maz Ameli
2e6bb7f669 Rename Tasks page to Dependency diagnostics and update labels (#67935) 2026-01-08 19:23:03 -05:00
Egor Grushin
c822a6228c GIT-8461 hide "Visualize another way" button for Sankey charts (#67753) 2026-01-08 23:46:37 +00:00
Phoomparin Mano
2229469ca4 Add documentation button to tenants list page (#67884) 2026-01-08 23:03:36 +00:00
Egor Grushin
43ad099236 fix flake unit test (#67942) 2026-01-08 21:53:50 +00:00
Braden Shepherdson
b496e05834 [perf] Add a unit test for #66955 as a follow-up (#66958) 2026-01-08 16:18:09 -05:00
Gabriel Moreno
2847a18d60 UXW-2623 Update dependency graph labels and icons for sql questions (#67870)
* feat: include query type on dependencies api response

* feat: show icons based on query type

* test: add unit spec for dependency graph utils

* refactor: restore changes after merge conflict
2026-01-08 16:05:42 -04:00
Braden Shepherdson
413b32e277 [perf] Expand the qp.perf-test benchmark suite (#65806)
Lots of new tests, mostly aimed at seeing how the lib and QP scale on
clear dimensions: more stages, wider tables, joins, big expressions.
2026-01-08 19:43:10 +00:00
Alex Yarosh
4a2fade226 Revert "remove transforms once again (#67809)" (#67945)
This reverts commit 7f08349271.
2026-01-08 14:27:24 -05:00
Gabriel Moreno
117e2a22a3 UXW-2629 Adjust library breadcrumb folder expansion behavior (#67862) 2026-01-08 15:25:24 -04:00
Braden Shepherdson
cd5bc6bf72 [QP] Reject fuzzy match of join condition LHS to that join's RHS (#67804)
Fixes #67667.

`lib.equality` has logic to do "fuzzy" matching of field refs with
the corresponding columns. This logic exists to support somewhat
malformed older queries with impoverished field refs. Refs in healthy
recent queries are fully specified and there's nothing ambiguous to
required the fuzzy matching.

The bug #67667 caught a case where this fuzzy matching could find a
column with the same name on the RHS of a join, if the original target
column has disappeared from an upstream query.

This change causes the QP to fail in exactly this case: when a would-be
LHS ref in a join condition ends up pointing at the RHS of the same
join. That would produce a strange join condition like
`LEFT JOIN Orders ON Orders.ID = Orders.PRODUCT_ID`
which produces incoherent results, and could result in a very costly
Cartesian join.

This is a user-level error, since the query is broken and needs repair.
2026-01-08 14:13:34 -05:00
kevinkelleher12
f1626f8a81 Fix search links for actions and segments 2026-01-08 19:03:19 +00:00
Nemanja Glumac
c82582de0c Provide Cypress env (CI) for the support file (#67934) 2026-01-08 18:49:56 +00:00
Nemanja Glumac
d124262aca Fix typo in a group membership endpoint (#67923) 2026-01-08 12:36:32 -06:00
Aleksandr Lesnenko
22fa6d762a skip flaking loki bar chart spec (#67929) 2026-01-08 18:26:29 +00:00
William
c771b10ea8 Readded fk field ids to v_content's fk fields (#67867)
Basically, the issue is that trying to implicit join using the instance analytics content model's made_public_by_user field made qp throw an error. The underlying problem is that the field in question wasn't defined as a foreign key, even though the model's result metadata claimed it was a foreign key. Updating the field to actually be a foreign key fixed the problem. This also applies to the content model's question_database_id field, which was also fixed.
2026-01-08 10:57:49 -06:00
Nemanja Glumac
98adee8b12 Fix typos in Metabot code (#67918) 2026-01-08 17:18:17 +01:00
Nemanja Glumac
7fe74f70f8 Fix typo in test metadata (#67909) 2026-01-08 14:58:36 +00:00
Riley Thompson
63ce826faa Use source alias for breakout with implicit join (#67480)
* use source alias if we have a fk-field-id

* try only on single stages

* try to identify implicit joins

* try fix

* Clean up

* move test and test all drivers

* move test

* only test drivers with left join feature

* adjust length for certain drivers

* smaller for mysql

* fix starts-with filter

* improve test

* case insensitive filter for h2

* move let bindings up
2026-01-08 14:55:19 +00:00
Nemanja Glumac
63f180034d Fix typos in FE enterprise code translations (#67908) 2026-01-08 15:45:37 +01:00
Anderson
89fa63c99b Show Metabot button on transform creation page (#67837) 2026-01-08 11:19:40 -03:00
Timofey Kachalov
670828db79 Fix flaky "shows a static dashboard using drills" e2e (#67874) 2026-01-08 17:43:16 +04:00
Timofey Kachalov
88684d3b2c fix(embed-js, sdk): Properly handle restricted collection access in MetabaseBrowser (#67523) 2026-01-08 16:47:53 +04:00
Phoomparin Mano
d7b8e86987 Remove static llms.txt and embedding/llms.txt (#67878) 2026-01-08 19:45:56 +07:00
kevinkelleher12
322a6a0323 Reroute admin/tenants to admin/people/tenants (#67869) 2026-01-08 07:34:21 -05:00
Timofey Kachalov
d5b070b8a3 fix(SDK, Embed JS): Hide Static Question topbar from DOM when no children rendered (#67852) 2026-01-08 14:33:40 +04:00
Timofey Kachalov
aa5a35f94c Add support for content translations for auth embeds (#67730) 2026-01-08 14:33:01 +04:00
Romeo Van Snick
adf35e2c4c Use formatting settings for date parameters (#67713)
* Use instance settings for date filters in parameters

* Fix test instance to use default time format

* Add unit tests for date paramater formatting with custom settings
2026-01-08 14:23:42 +11:00
Alexander Polyankin
da9fbb67a2 Dependencies - unreferenced & broken items (#66279)
* entity check jobs seems to work

* reset analysis version of children when updating a card or transform

* transform event tests

* event handlers actually update analyses

* transform runs update dependents and api exists

* initial changes

* params

* fixes

* Fix

* Fix

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* X

* Fix

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fix

* Fixes

* Fixes

* Fixes

* Fixes

* added more tests

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Columns

* Fixes

* Errors column

* Fixes

* Revert "added more tests"

This reverts commit c7188e55dd.

* Fixes

* Revert "Revert "added more tests""

This reverts commit 66b2b7efd9.

* fix compilation

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Add link

* make query validation errors consistent and return them in the broken api

* use the same table

* Fixes

* Fixes

* Fixes

* /graph/broken and /graph/unrecognized match /graph

* Fixes

* Polish

* possibly fix check_card 500

* Fixes

* refactor query-error

* add test for validating sql column with no available sources

* backfill correctly finds dashboard dependencies

* fix comment wording

* bump current-analysis-version

* revert error type names

* make validation exceptions store errors in the standard format

* rename unknown-error to validation-error

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fix

* Fixes

* panel

* Fixes

* Fixes

* Fixes

* Save

* Fixes

* Add missing types

* Fixes

* Fixes

* Fixes

* also analyze segments

* add more tests

* Fixes

* Fix

* Fixes

* Fixes

* status

* Hide dependencies when not analyzed

* Tests

* Tests

* Tests

* Tests

* Tests

* Fixes

* Fixes

* Remove columns

* run backfills immediately during test startup

* remove token checks for maintaining dependencies

* run dependency backfill on serdes

* Tests

* Fixes

* Fixes

* Fix types

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* fix bug involving nonstandard tag spacing

* fix some broken tests

* Tests

* Tests

* Fixes

* Tests

* Fixes

* FixesTests

* Fixes

* Fixes

* Tests

* Fixes

* Fixes

* Fixes

* Fixes

* fix another test

* Fixes

* Add missing info

* Fix tests

* Hydrate collection for snippets

* Fix

* Fixes

* revert unnecessary change

* some lint fixes and a bunch of schemas

* fix compilation

* lint fixes

* new events derive from metabase/event

* simply specs to work with open-api spec gen

* dependency backfill checks tokens again

* Fixes

* fixed tests

* don't use ::ns/blah in a #_ comment when ns isn't in scope

* fix more tests

* add and update more tests

* lint fixes

* fix linting and make lib changes backwards compatible

* maybe fix more tests?

* fix ns name

* fix another test

* update modules config

* fix one test and debug second

* more test debugging

* yet more test debugging

* fix test?

* fix more tests?

* revert another unexpected migration change

* fix another test

* fix linting

* fix more tests

* update openapi spec

* fix unrelated bug with nil ancestors

* add test for nil ancestors bug

* Remove /status call

* Merge

* Fixes

* Fixes

* Fixes

* Fixes

* review feedback

* more cleanup

* yet more cleanup

* support unnormalized snippet tags

* more review feedbac

* fix build

* fix linting

* update lib.parameters.parse to match driver.common.parameters.parse

* fix compilation

* fix tests

* fix more tests

* fix more tests

* possibly fix linting

* fix more tests

* fix even more tests

* maybe fix tests?

* actually make backend support currently impossible snippet names

* Use TreeTable

* Remove unused component

* Renaming

* FE fixes

* switched migration to 59

* fully revert 58 migrations

* most review feedback

* factor out common setup from events tests

* deduplicate analysis gen tests

* more test fiddling

* final review feedback

* actual final review feedback

* linting

* Fix merge

* Fix lint

* reformat

* add measures to spec

* fix final test

* Fix links

---------

Co-authored-by: William Zimrin <william@metabase.com>
2026-01-07 21:57:09 -05:00
github-automation-metabase
314122dee5 Update generated docs (master) (#67890)
Co-authored-by: github-actions <github-actions@github.com>
2026-01-07 21:50:19 -05:00
Nick Fitzpatrick
3975adb932 Color Key Cleanup (#65855)
* Migrating Color Keys

temp

background keys

fixing some errors

border colors

removing duplicate keys

types

* enforce types on c prop

* more type cleanup

* rebase catch up

* unit tests

* re-add embedding sdk setup plugin

* e2e tests

* Sankey chart using correct label color in static viz, fix background detection

* some loki changes

* adjust border color

* sdk: updated sdk color mapping

* type adjustments, unit test fixes

* loki tests passing

* last e2e test

* cleanup

* Update Loki Snapshots

* updating alert colors

* Claude nits

* Update Alert Loki tests

* text-tertiary

* Update Loki Snapshots

* missed one

* last adjustmnet

* Update Loki Snapshots

* text-white

---------

Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-07 21:15:01 -04:00
Aleksandr Lesnenko
65a2afa186 Let users with data model perm access data studio (#67653)
* let users with data model permission access data studio

* respect manage table metadata permission in data studio

* fix ci

* fix flaky specs

* review

* review
2026-01-08 01:14:00 +00:00
Alexander Polyankin
c65cbf7791 Remove description (#67887) 2026-01-07 16:26:04 -08:00
Alexander Polyankin
42312e5fc2 Allow to overwrite id only for native models (#67773) 2026-01-07 23:56:31 +00:00
Egor Grushin
376ff5d1cf UXW-49 fixing log scale axis value (#67668)
Use a linear scale for values between 0 and 1, and a logarithmic scale for values greater than 1.
2026-01-07 22:54:03 +00:00
Aleksandr Lesnenko
8cbc058a0c table measures (#66576)
---------

Co-authored-by: Tamás Benkő <tamas@metabase.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
2026-01-07 22:41:11 +00:00
Romeo Van Snick
6b04138204 Add tooltip to run button when field filters are missing a target field in Native editor (#67670)
* Add e2e test for missing field mapping

* Make validateTemplateTags public

* Render errors in run button tooltip

* Pass errors to run button

* Fix selector in test

* Simplify test

* Try with realClick

* Add Lib implementation of validateTemplateTags

* Also validate display-name

* Use Lib implementation of validateTemplateTags

* Localize error messages

* fixup! Add Lib implementation of validateTemplateTags

* Add Lib.ValidationError type

* Remove unused code

* Also validate temporal-units dimension

* Use validate-template-tags in can-run

* Add tag-name to template tag errors

* Fix malli types

* Add tests for validate-template-tags

* Add tooltip to save button too

* Also test time grouping and save button

* Remove more unused code

* Remove simple wrapper

* Use cond-> pattern instead of filter identity
2026-01-08 09:26:43 +11:00
Phoomparin Mano
65d34e4e37 Add GitHub actions to generate llms.txt and llms-embedding-full.txt at repo root during release (#67737)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
Co-authored-by: github-automation-metabase <166700802+github-automation-metabase@users.noreply.github.com>
2026-01-07 22:17:34 +00:00
Phoomparin Mano
fd6740eee7 Block official collections in shared collections and its subcollections (#67537) 2026-01-08 05:12:16 +07:00
Riley Thompson
18cf4fac85 fix typo (#67863) 2026-01-07 16:44:43 -05:00
da
17349e4f12 Fix logging messages for field values updates (#66767)
We're logging "Field Field xxx xxxx". I'm just simplifying that log line
2026-01-07 14:43:59 -06:00
kevinkelleher12
bfb78b8d6a Fill line series symbol with appropriate color in dark mode (#67811) 2026-01-07 18:41:03 +00:00
Rodrigo López Dato
343ae8d213 Fix -{un,}install-merge-drivers when using a git worktree (#67865) 2026-01-07 15:28:25 -03:00
kevinkelleher12
e69b260f0b Fix dark text on dark verification tooltip background in light mode (#67799) 2026-01-07 12:13:49 -05:00
Anderson
336180ee0c Make stacked row chart tooltips use custom display names (#67706)
* Make stacked row chart tooltips use custom display names

* Change the way we override seriesName with custom title
2026-01-07 12:16:57 -03:00
Nemanja Glumac
d5925e28f7 Bump Storybook to 8.6.15 (#67473) 2026-01-07 15:52:37 +01:00
Jakub Chodorowicz
5bc3af2630 update husky to v9 (#67846) 2026-01-07 15:41:35 +01:00
kevinkelleher12
c5f433336a add kevinkelleher12 to team.json and github-slack-map.json (#67752) 2026-01-07 08:25:39 -05:00
Dan Stone
dca8465cfb Index incremental filter column for OLTP databases (#66478)
* Add indexes to incremental checkpoint filter columns

* Fix bad barf

* Fix drop-index arg-list

* Less indirect supports test

* Comment on sync order

* Cleanup driver changelog entry

* Move changelog note back to 0.58 (backport)

* Fix passive voice
2026-01-07 12:36:53 +00:00
Alexander Polyankin
618e6e8701 Hide graph watermark (#67839) 2026-01-07 02:13:36 +00:00
Romeo Van Snick
6f637ee050 Test coercion strategy (#67496)
* Also test coerced datetime column

* Add e2e reproduction for opening the datetime filter for coerced fields

* Also check :effective-type in original-isa

* Fix test
2026-01-07 11:19:18 +11:00
github-automation-metabase
c06b4c2511 Update translations 2026-01-06 (#67800)
* Update translation sources 2026-01-06

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-07 00:13:27 +00:00
Alex Yarosh
7cdbdc8e94 docs: Add redirect for interactive embedding quickstart guide (#67833)
* Add redirect for interactive embedding quickstart guide

* Add redirect for quick-start guide
2026-01-06 18:48:13 -05:00
dpsutton
1bcc022f6b Reduce number of modules that trigger driver tests (#67769)
Before:

76 modules trigger:

```clojure
mage.modules=> (let [deps (dependencies)
                     all-deps (keys deps)]
                 (reduce (fn [acc module]
                           (if (driver-deps-affected? deps [module])
                             (conj acc module)
                             acc))
                         []
                         all-deps))
[actions analytics analyze api api-keys app-db appearance audit-app auth-identity auth-provider batch-processing cache channel classloader collections config content-verification dashboards database-routing driver driver-api eid-translation embedding events formatter initialization-status internal-stats legacy-mbql lib lib-be logger login-history model-persistence models notification parameters permissions pivot plugins premium-features public-sharing pulse queries query-permissions query-processor remote-sync request search secrets server session settings setup sso startup sync system task task-history tenants timeline types upload users util version view-log warehouse-schema warehouses enterprise/advanced-permissions enterprise/api enterprise/impersonation enterprise/sandbox enterprise/scim enterprise/serialization enterprise/sso]
mage.modules=> (count *1)
76
```

After:

Only 28 modules trigger driver tests:
```clojure
mage.modules=> (let [deps (dependencies)
                     all-deps (keys deps)]
                 (reduce (fn [acc module]
                           (if (driver-deps-affected? deps [module])
                             (conj acc module)
                             acc))
                         []
                         all-deps))
[actions analyze app-db cache database-routing driver driver-api legacy-mbql lib lib-be logger model-persistence models parameters pivot plugins premium-features queries query-permissions query-processor sync tenants upload warehouse-schema warehouses enterprise/advanced-permissions enterprise/impersonation enterprise/sandbox]
mage.modules=> (count *1)
28
```

How does this magic work? Just with an exclusion list:

```clojure
mage.modules=> driver-affecting-overrides
 #{batch-processing timeline eid-translation version
 enterprise/serialization initialization-status session users enterprise/api login-history sso classloader
 enterprise/sso permissions request view-log system api task-history notification task dashboards startup config
 content-verification secrets server formatter events util settings channel search collections remote-sync types
 api-keys setup enterprise/scim audit-app analytics public-sharing pulse embedding auth-identity auth-provider
 appearance internal-stats}
```
2026-01-06 16:13:33 -06:00
Anderson
0d13842be7 Fix dependency graph zoom controls colors in dark mode (#67774)
* Fix dependency graph zoom controls colors in dark mode

* Do not use :global
2026-01-06 22:00:37 +00:00
Phoomparin Mano
a7d35f1baf Add a tooltip message if model persistence is unsupported for a database (#67566) 2026-01-07 04:09:29 +07:00
Sloan Sparger
0c04a6a3c1 [Metabot] Split up metabot.unit.spec.tsx (#67764)
* init pass at adding an error boundary to metabot

* update the illustration used for error boundary and remove simulated error ui

* add unit tests

* split up the mega metabot.unit.spec.tsx unit test file

* fix lint
2026-01-06 14:47:18 -06:00
Jeff Bruemmer
1888c80fff 58 as latest (#67820) 2026-01-06 15:42:50 -05:00
Alex Yarosh
c1f08f65a6 docs: remove temp tenants docs (#67819)
* remove temp tenants

* jwt

* more link
2026-01-06 14:43:50 -05:00
Jeff Bruemmer
844123dbf2 docs - note on subscriptions (#67816)
* note on subscriptions

* typo
2026-01-06 18:54:00 +00:00
Alex Yarosh
ebd1476a1e docs: tenants (#67474)
* tenants

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* links

* add links and images and edit remote sync

* links

* one more link

* Optimized 12 images, saved 930.1 KB (47.9% smaller)

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* edits

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-01-06 18:47:27 +00:00
Alex Yarosh
78263d64ce documents oss (#67810) 2026-01-06 18:19:25 +00:00
Alex Yarosh
7f08349271 remove transforms once again (#67809) 2026-01-06 13:19:19 -05:00
Jakub Chodorowicz
bfa61de71f add all .env file except .env.example to gitignore (#67793) 2026-01-06 18:27:13 +01:00
Sloan Sparger
d1a55ddff1 [Metabot] Metabot error boundary (#67749) 2026-01-06 11:02:26 -06:00
Nicola Mometto
4e3d8f0caf Move metering events off the token check (#67584)
* chore: remove private from token check defs

* feat: don't send metering stats during token check

* add task for sending metering events

* lift try-catch

* add tests

* move around

* remove duplicate set!

* send ints/bools as strings, for backwards compatibility

* reduce metering frequency

* configurable interval, clamped between 1 min and 12 hours
2026-01-06 16:46:32 +00:00
Nicola Mometto
75ab330328 Add transform metrics to anonymous stats ping (#67786)
* feat: add transforms metrics

* feat: send transform metrics

* fix: don't require transforms feature, we send stats if we disabled the feature

* add tests

* fix: ee test
2026-01-06 15:42:03 +00:00
Ryan Laurie
69abc4cf1c fix translations workflow permissions (#67794) 2026-01-06 15:37:58 +00:00
Noah Moss
6cef5f80d0 Misc cleanup in Metabot clojure code (#67701)
* Misc cleanup in Metabot clojure code

* More misc cleanup

* Lint
2026-01-06 09:27:32 -05:00
Maksym Yakubych
5dd7e2049e chore: add myself to team.json and github-slack-map.json (#67754) 2026-01-06 11:19:09 -03:00
John Swanson
2393146b8c perms for moving collections with archived kids (#67728)
Previously if you had:

```
A (curate)
  B (curate)
    C (no permissions)
      D (curate)
```

Then if C was archived, you would be unable to move or archive A or
B.
2026-01-06 04:42:49 -08:00
Mahatthana (Kelvin) Nomsawadi
112d1d0235 Fix pie chart label not visible on dark theme (#67639)
* Fix `text-secondary` not working on dark theme on charts

* Support all colors so it's easier to reason about

* Add tests

* Fix type error

* Revert part of the code that's not used anymore

* Add test snapshots

* Make overriding font more consistency across environments

e.g. From storybook to SDK to the main app.

* Fix formatting
2026-01-06 12:34:27 +00:00
Sébastien
3f2ad43a43 Fix MB in an iframe running on a subpath (#67724)
* fix MB in an iframe running on a subpath

* fix

* extracted out the util fn and added unit tests for it

* addressed comments

* fixed unit tests
2026-01-06 13:19:02 +01:00
github-actions[bot]
835b3efc27 Update translations 2026-01-06 (#67782)
* Update translation sources 2026-01-06

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-06 11:58:16 +01:00
Romeo Van Snick
d8d4537f29 Fix broken python e2e test (#67435) 2026-01-06 10:00:38 +01:00
Nemanja Glumac
3f35a82ea7 Upgrade jspdf (#67760) 2026-01-06 08:58:38 +01:00
Maz Ameli
a1a62cd603 Add keyboard shortcut to close/open side menu in Data Studio (#67413)
* add keyboard shortcut and tooltip

* refine tooltip position and delay

* also listen for left bracket [ key
2026-01-06 00:56:48 +00:00
Romeo Van Snick
8542738fe7 Add repro for metabase#45890 (#67669) 2026-01-06 09:57:51 +11:00
bryan
f290bbbbe0 Skip cloud driver tests when possible + consolidate test skipping logic (#67568)
* Skips cloud driver tests on PRs unless files changed

Cloud drivers (Athena, BigQuery, Databricks, Redshift, Snowflake) now
only run on PRs when their files changed or 'ci:all-cloud-drivers' label
is present. Full coverage maintained on master/release branches.

* [do not merge] add failing databricks test

* Revert "[do not merge] add failing databricks test"

This reverts commit de5b6fa602.

* empty commit

* Fix cloud driver skip logic to respect ci:all-cloud-drivers label

The previous condition had three checks that could block cloud drivers:
1. !inputs.skip - false when no backend files changed
2. skip != 'true' - from mage can-skip-driver-tests
3. X-should-run == 'true' - the per-driver decision

The problem: checks 1 and 2 would override check 3, so the label had no
effect. Even with ci:all-cloud-drivers, cloud drivers were skipped.

We don't need inputs.skip or can-skip-driver-tests for cloud drivers
because the X-should-run output already encapsulates the full decision:
- master/release branch → run
- ci:all-cloud-drivers label → run
- driver files changed → run
- otherwise → skip

The label is an explicit override, so it should work even on PRs with no
backend changes. Removing the redundant checks lets the label work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* mage -driver-decisions + roll in module analysis

* Remove quarantine check from test-driver action

Quarantine logic is now consolidated in mage -driver-decisions.
The check happens earlier in determine-driver-skips, so quarantined
drivers get should-run=false and their jobs never start at all.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fail CI if quarantined driver has file changes without break-quarantine label

If you change files in a quarantined driver's module (e.g., modules/drivers/snowflake/)
but don't add the break-quarantine-<driver> label, a new check-quarantine-conflicts
job will fail with a clear error message.

This prevents accidentally merging changes to quarantined drivers without running
their tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add --github-output-only flag to mage driver-decisions

Instead of using grep to filter mage output, the task now supports two modes:
- Default: prints human-readable analysis + GITHUB_OUTPUT preview
- --github-output-only: prints only clean key=value lines for CI

The workflow now calls mage twice: once for debugging visibility,
once with --github-output-only redirected to $GITHUB_OUTPUT.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add quarantine conflict checks to all driver jobs

Extends the quarantine conflict detection to ALL drivers, not just cloud
drivers. When a driver is quarantined but has file changes in
modules/drivers/<driver>/, the job will run but immediately fail with
a clear error message explaining how to add the break-quarantine label.

Changes:
- Add quarantine conflict check steps to presto-jdbc, sparksql, sqlite,
  sqlserver, and vertica jobs
- Update login-to-ecr job condition for vertica quarantine conflicts
- Fix verbose output suppression in --github-output-only mode by adding
  verbose? parameter to changes-important-file-for-drivers?

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add driver decision priority documentation and tests

Adds comprehensive documentation to driver-decision function showing the
priority order as a table, plus explanations of what triggers "driver
module affected" and the difference between cloud vs self-hosted drivers.

Adds mage.modules-test with 14 tests (78 assertions) covering:
- Quarantine logic and break-quarantine labels
- Global skip behavior
- H2 always-runs behavior
- Master/release branch behavior
- Driver module affected behavior
- Cloud driver special rules (labels, file changes)
- Self-hosted driver skip logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Comment out starburst from driver-directory mapping

Starburst tests are currently disabled in drivers.yml, so the mapping
entry was inconsistent with all-drivers list. Commented out with a note
explaining why, so it can be easily re-enabled when starburst tests
come back.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* silence messages when in github-output-only mode

* remove redundant cloud-driver change detection

- this happens inside the script instead

* get rid of redundant rules definitions

- now only print how we make decisions in help for the task

* make a temporary redshift change

* Revert "make a temporary redshift change"

This reverts commit 3d93c60368.

* format usage fn code

* light refactor

* Rename driver decision variables for clarity and flatten decision tree

- driver-module-affected? → driver-deps-affected? (module dependency graph)
- drivers-changed → particular-driver-changed? (specific driver's files)
- Reorder priority: skip/H2/master now before quarantine
- Flatten nested cond for cloud driver rules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Quarantine now respected on master/release branches

- Move quarantine check before master/release in driver-decision priority
- Quarantined drivers are now skipped even on master/release (unless break-quarantine label)
- Update tests and priority table documentation to reflect new order
- Cloud drivers don't benefit from driver-deps-affected (only label or file changes)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 16:15:58 -06:00
Nemanja Glumac
1f366dde49 Update copyright year in README.md (#67677)
It's that time of the year again...
2026-01-06 11:05:33 +13:00
Aleksandr Lesnenko
edeea2ead0 fix saved question intro modal layout (#67703) 2026-01-05 21:23:25 +00:00
appleby
fbdf7574ed Fix parsing of :ERROR chunks in metabase-enterprise.metabot-v3.util/aisdk->messages (#67674)
* Fix parsing of :ERROR chunks in metabase-enterprise.metabot-v3.util/aisdk->messages

There was a typo in the case expr where :ERROR chunks were being handled like :DATA chunks, but in fact should be
handled like :TEXT chunks. This was resulting in an error like

    1. Unhandled java.lang.ClassCastException
       class java.lang.String cannot be cast to class
       clojure.lang.Associative (java.lang.String is in module java.base
       of loader 'bootstrap'; clojure.lang.Associative is in unnamed
       module of loader 'app')
                       RT.java:  847  clojure.lang.RT/assoc
                      core.clj:  193  clojure.core/assoc
                      core.clj:  192  clojure.core/assoc
                      util.clj:   56  metabase-enterprise.metabot-v3.util/aisdk->messages/fn/fn
                      ...

whenever an :ERROR chunk was encountered as we tried to ASSOC a string where we were expecting a map.

https://v4.ai-sdk.dev/docs/ai-sdk-ui/stream-protocol#text-part
https://v4.ai-sdk.dev/docs/ai-sdk-ui/stream-protocol#error-part

059d904d6e/ai_service/ai_sdk.py (L50)
059d904d6e/ai_service/ai_sdk.py (L203)
059d904d6e/ai_service/ai_sdk.py (L324)

* Add some error chunk parsing tests to aisdk-line-parse-test

* Mark aisdk-line-parse-test as ^:parallel

This does io to read some files, but should be threadsafe as no other tests read or modify those files.

* Add make-mock-error-stream-response test util

And rename make-mock-stream-response to make-mock-text-stream-response

* Add client-error-test to test streaming-request with error chunks in response
2026-01-05 12:38:04 -08:00
Sloan Sparger
a2aea53b1c [Metabot] Update Metabot icon (#67741) 2026-01-05 13:29:48 -06:00
metamben
d972f4529f Patch malli to avoid OOM related to recursive memoization (#67733)
This is a temporary fix until https://github.com/metosin/malli/pull/1250 gets merged into Malli.
2026-01-05 21:46:29 +03:00
Noah Moss
f1f47d4050 Clarify permissions model for suggested prompts generation (#67656)
* Run suggested prompts generator as admin & fix test

* Add a prompt suggestions GET perms test

* small cleanups

* use mbql5
2026-01-05 13:33:26 -05:00
dpsutton
476f61760c Handle unroutable token checks (#67698)
We have a grace periods and circuit breakers for token checks. But one
issue is that if the token check doesn't throw an error we can't catch
it.

An easy way to see this is to use a local network address that won't
respond like 192.168.random.random (i used 192.168.40.40) then see the
behavior. Without the timeouts, the threads all just get stuck here and
the page never loads. With timeouts, you'll see a few stutters until the
circuit breaker steps in, at which point you have a non-enterprise
version.

https://www.loom.com/share/6ae056dc126b48c9abe8a7ad9366fd05
2026-01-05 11:52:56 -06:00
Copilot
b24727409c Migrate React components from dispatch(addUndo) to useToast hook (#66778)
* Update React components to use useToast hook instead of dispatch(addUndo)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

# Conflicts:
#	enterprise/frontend/src/metabase-enterprise/tenants/containers/NewTenantModal/NewTenantModal.tsx
#	enterprise/frontend/src/metabase-enterprise/tenants/containers/TenantActivationModal.tsx
#	frontend/src/metabase/admin/people/components/GroupDetail.tsx

* type fix

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-01-05 10:48:54 -07:00
dpsutton
119487b1cc remove api "uses" dependency on api-routes (#67650)
* remove api "uses" dependency on api-routes

api-routes can use all modules to expose their routes. ie it uses
timeline module, etc. It has `:uses :any`.

```clojure
mage.modules=> (let [deps (dependencies)
                     all-deps (keys deps)]
                 (reduce (fn [c module]
                           (update c (if (skip-driver-tests? deps [module])
                                       :skip :run) inc))
                         {:skip 0 :run 0}
                         all-deps))
{:skip 0, :run 153}
```

This is shown in this path here:

```clojure
mage.modules=> (let [ds (dependencies)
                     ds (into {}
                              (map (fn [[k v]] (if (= v :any)
                                                 [k (-> ds keys set)]
                                                 [k v])))
                              ds)]
                 (letfn [(driver-path [to]
                           (loop [q '[[driver]]
                                  seen #{}]
                             (let [p (first q)]
                               (when-let [node (peek p)]
                                 (if (= node to)
                                   p
                                   (recur (into (vec (rest q))
                                                (for [adjacent (remove seen (ds node))]
                                                  (conj p adjacent)))
                                          (conj seen node)))))))]
                   (driver-path 'enterprise/remote-sync)))
[driver warehouse-schema api api-routes enterprise/remote-sync]
```

driver uses arehouse-schema uses api uses api-routes which uses
any. Therefore all changes will trigger driver tests.

So after these changes we observe:
- the path above is empty (drivers don't transitively use remote-sync
module) and therefore would not trigger driver tests
- only 76 modules trigger driver tests

```clojure
mage.modules=> (let [deps (dependencies)
                     all-deps (keys deps)]
                 (reduce (fn [c module]
                           (update c (if (skip-driver-tests? deps [module])
                                       :skip :run) inc))
                         {:skip 0 :run 0}
                         all-deps))
{:skip 77, :run 76}
```

What else did i try?

1. add a `#_{:clj-kondo/ignore [:metabase/modules]}` to the ns
I didn't love this because it felt a bit like cheating. All of this is
kinda annoying because it's fundamentally about changes during dev time.

2. remove the ns require and add a requiring-resolve
This actually doesn't break the module usage analysis. It's smart enough
to see this so this just makes it more tenuous and easy to miss if we
change anything while also still leaving in place the module
entanglement.

So I just fire the event from the api module when rebuilding routes and
handle the event from the api-routes module. The trick is that the api
module sends along the function to rebuild the docs

* handle cycling ref

* remove reference to deleted file

* our linter is scared of an extra line

* use an events namespace

not doing an init namespace as that's similar but not the same. Those
are for settings and models. It's fine to just require the event
namespace in the core namespace. it's a bit of ceremony but the pattern
is useful

* include random event correctly

used to be just `(first (descendants :metabase/event))`. This was
fragile and just now started to fail:

```clojure
models-test=> (first (descendants :metabase/event))
:metabase.api-routes.events/api-events
```

because of course do we things like `(derive ::api-events
:metabase/event)`.

```clojure
models-test=> (filter (comp (complement #{"event"}) namespace)
                      (descendants :metabase/event))
(:metabase.api-routes.events/api-events
 :metabase.audit-app.events.audit-log/card-event
 :metabase.audit-app.events.audit-log/cloud-add-on-event
 :metabase-enterprise.dependencies.events/transform-delete
 :metabase.activity-feed.events.recent-views/legacy-card-event
 :metabase.view-log.events.view-log/collection-read-event
 :metabase.audit-app.events.audit-log/notification-handler-event
 :metabase.audit-app.events.audit-log/user-update-event
 :metabase-enterprise.dependencies.events/transform-run
 :metabase.revisions.events/transform-event
 ...
 )
```

This has been lucky for a long time
2026-01-05 11:28:46 -06:00
Anderson
a5afeea12d Update Remote Sync branch picker to match new designs (#67620)
* Update Remote Sync branch picker to match new designs

* Move git sync controls next data studio logo

* Fix unit test

* Fix e2e test

* Address Claude's review

* Remove console.error

* Use css modules for the chevron icon transition

* Use popover instead of findByRole('presentation')
2026-01-05 17:21:58 +00:00
Ryan Laurie
4521f75ee6 stabilize flaky test (#67646) 2026-01-05 14:05:56 -03:00
Noah Moss
cfdd4de405 try to fix flake in semantic index dlq tests (#67700) 2026-01-05 09:22:27 -05:00
Noah Moss
24f586428d Disable progress bar in whitespace linter github actions workflow (#67695)
* disable progress bar in whitespace linter github actions workflow

* add extra whitespace to demonstrate failure

* Revert "add extra whitespace to demonstrate failure"

This reverts commit ba34650efd.
2026-01-05 09:21:56 -05:00
Nemanja Glumac
0128771ad1 Revert "Replace Cypress grep with Bahmutov's cy-grep (#67660)" (#67725)
This reverts commit d2d8d1fe83.
2026-01-05 14:06:11 +00:00
Timofey Kachalov
e3f05d0cbb Don't close InteractiveQuestion editor on Filters change (#67517) 2026-01-05 17:02:24 +04:00
Dan Stone
53203af754 Add some additional incremental transforms tests (#67683)
* Add some additional incremental transforms tests

* Add missing require

* Use driver/table-name-length-limit
2026-01-05 11:02:08 +00:00
Aleksandr Lesnenko
71c188c09f Use tree table in data model (#67117)
* use tree table in the data model section of data studio

* review
2026-01-02 18:05:57 +00:00
Nick Fitzpatrick
db48071330 Don't show metrics in the join step (#67490) 2026-01-02 13:01:25 -04:00
Nick Fitzpatrick
05d04cf64b specify gauge label sizes in px (#67386) 2026-01-02 12:54:35 -04:00
Nick Fitzpatrick
6c99df07a8 Adding e2e repro for drill through entity keys (#67467) 2026-01-02 12:54:19 -04:00
Alex Yarosh
5b92cc2b02 Improve formatting and clarity in serialization.md (#67587)
Updated curl command formatting and clarified instructions for exporting and importing Metabase data.
2026-01-02 10:41:15 -05:00
Vamsi Peri
fea1cbad4b Update issue templates (#67687)
* Update issue tempaltes

* Delete .github/ISSUE_TEMPLATE/task.md

* Update verbiage for new feature request
2026-01-02 10:24:50 -05:00
Jakub Chodorowicz
024c43ff39 fix: broken date filter test (#67684) 2026-01-02 16:18:14 +01:00
Edward Paget
ff4f2bf956 feat: add git settings modal to data studio (#67178)
* feat: add git settings modal to data studio

* Refactor GitSettingsModal to reuse existing settings form / Adjust some styles

* Fix and improve unit tests

* Adjust font size according to variant

* fix unit test

* fixup! mock API not other plugins in this layout

* Split unit test files and improve endpoints setup

* Implement PLUGIN_REMOTE_SYNC.GitSyncSetupMenuItem with internal rendering condition

---------

Co-authored-by: Anderson <anderson@metabase.com>
2026-01-02 11:55:52 -03:00
Nemanja Glumac
d2d8d1fe83 Replace Cypress grep with Bahmutov's cy-grep (#67660) 2026-01-01 12:33:26 +01:00
Eric Normand
e5ab9db7bc Extra remapped fields (#67601)
* kick ci

* Disable remaps when calculating columns for a query.

* Add tests for result_metadata remappings

* Add comments

* Whitespace
2025-12-31 19:07:17 +00:00
Braden Shepherdson
4786076692 [dashboards] Handle parallel FKs with dashboard filter values (#66287)
Fixes #65838.

This issue was about dashboard filters showing the wrong value when
the filter was bound to an FK field from a table with multiple FKs to
the same foreign table. The dashboard parameters logic on the BE was
choosing which FK to use for the filter values arbitrarily, meaning that
binding the filter to one of them would work fine, but the other would
give incoherent results.

The fix is to be deliberate about selecting the parameter's column. That
doesn't solve all ambiguous cases, but we really can't help if there's
a multi-hop join that has parallel edges in the middle!
2025-12-31 11:46:34 -05:00
Nicola Mometto
1e3a879116 Mage python runner (#67265)
* disable chunked encoding if using path style access

* mage task to start python runner with mock s3
2025-12-31 11:03:13 +00:00
Aleksandr Lesnenko
2c01e5063b series limit for row chart (#67419) 2025-12-30 20:08:11 -05:00
Ryan Laurie
b4912b71f1 more entity cleanup (#66659) 2025-12-30 17:23:34 -07:00
Nathan Voxland
1d8b669f62 Avoid joins of remote_sync_object with actual tables (#67042) 2025-12-30 15:37:13 -06:00
Denis Berezin
25091a2fd1 UXW-603 unified picker for Document smart link (#67408)
* UXW-603 temp unified picker

* Add unified data picker

* Fix issues with tabs, add e2e tests

* Self review
2025-12-30 18:06:54 -03:00
Timothy S. Dean
6f00f47c47 Simpler fix than first attempt. (#67300) 2025-12-30 22:41:43 +03:00
Aleksandr Lesnenko
07e2560596 fix zoom resets on resize (#67420) 2025-12-30 13:15:21 -05:00
dpsutton
d47b9d6759 bumping deps: (#67638)
- https://github.com/metabase/metabase/security/code-scanning/543
  about snowflake's of grpc netty shaded. We already have this
  version elsewhere so now it matches
- https://github.com/metabase/metabase/security/code-scanning/549
  and https://github.com/metabase/metabase/security/code-scanning/557
  issue in databricks. We bumped that and now it uses the new coordinate
  `at.yawk.lz4/lz4-java 1.10.1`
- https://github.com/metabase/metabase/security/code-scanning/496 bump commons-lang3.
  actually just exclude it from the driver jar so it will be found on parent
  classpath with coordinate from deps.edn: `{:mvn/version "3.19.0"}`
2025-12-30 10:44:10 -06:00
Chris Truter
b222e32bdf Revert "Add transforms.target_database_id column (#66953)" (#67630) 2025-12-30 16:25:10 +00:00
Jakub Chodorowicz
390e559dc2 Prg 160 add field grouping format and group host and port fields (#64280)
* Add field grouping of host and port

* Add host and port settings to postgres, mysql

* Add host and port grouping to db drivers

* Add database story with host and port group

* Add groupFields unit tests

* Fix typo

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix missing tunnel parameter value

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Refactor and simplify field grouping function

* feat: add nested fields support for db format

* feat: remove id field, adapt new format foy postgres, mongo, mysql, remove leftovers

* feat: support nested fields, add backdrop component

* fix: group inputs loosing focus on type/render

* refactor: simplify custom containers logic

* style: adjust backdrop container style

* refactor: field mappers for db forms

* refactor: move host and port config to the new format

* refactor: cleanup old grouping approach

* refactor: remove unneeded property

* fix: typo in the html prop name

* internal: validate container style comping from BE

this value can be set be external drivers so it's better to validate  it

Signed-off-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>

* fix: type errors

* fix: driver translation test

* refator: use existing getFlattenedFields function

* fix: flatten properties for connection property uniquness

* backtrack from ssl grouping for mongo

---------

Signed-off-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-30 14:51:28 +01:00
John Swanson
44aa361a2c UXW-2586: Acquire locks before changing data permissions (#67201)
* Acquire locks before changing data permissions

Data permission have a read-modify-write cycle:

- we read the existing permissions to see what's currently set
- then we decide what to do (e.g. delete the existing DB level
  permissions to write a granular table-level permission)
- then we do the write

This has a race condition if multiple Metabase instances are modifying
permissions at the same time.

For example, say we have:

Initial state: `{:db_id 1 :table_id nil :perm_value :unrestricted}`

Instance A: set table 1 to :blocked
Instance B: set database to :blocked

T1: A reads state, sees db-level permission, plans to expand to table-level
T2: B reads state, sees db-level permission, plans to replace it
T3: A deletes db-level, inserts table-level rows for all tables
T4: B deletes db-level (no-op), inserts new db-level :blocked

Result (CORRUPT):
```
{:db_id 1 :table_id 1 :perm_value :blocked}      ;; from A
{:db_id 1 :table_id 2 :perm_value :unrestricted} ;; from A
{:db_id 1 :table_id nil :perm_value :blocked}    ;; from B
```

Both db-level AND table-level permissions now exist.

For the permissions API, we take a cluster lock, but sync operations
bypassed this cluster lock. This PR creates a lower-level cluster lock
per `[database, group, perm-type]` so only one instance/thread can do
the read/decide/write cycle for a particular db/group/perm at a time.

* Add a test for race conditions setting data perms

This took a while before I was able to track down the fact that using
`(mt/with-temp )` caused both threads to share the same connection, so
they could obtain the lock simultaneously 🤦

* Use a slightly coarser lock

I realized that if an instance has a huge number of groups, we'll obtain
a lock and ask Postgres to maintain an active savepoint for each group,
which might be untenable.

I think the best solution here is to use slightly coarser locks. This
might increase contention slightly, since we won't be able to change
permissions for `db 1, group 1, perm type view-data` at the same time
that we change permissions for `db 1, group 2, perm type view-data`. But
I think the tradeoff here is necessary.
2025-12-30 13:08:39 +00:00
Mahatthana (Kelvin) Nomsawadi
cf7026a6a2 Fix empty cards with no results making dashboard longer than expected (#67581)
* Prevent unnecessary height calculation

* Prioritize local layout from `react-grid-layout` for height calculation

* Refix the issue for real

* Add tests
2025-12-30 12:51:29 +00:00
Jakub Chodorowicz
afef9ac2ae fix: hide editing toggle for unsupported engines (#67564)
* fix: hide untested and unsupported db engines in table editing section

* move allowed engines to constants file

* test: add hidden editing toggle test case
2025-12-30 11:50:11 +01:00
Nemanja Glumac
b5f483d951 E2E workflows env vars cleanup (#66592) 2025-12-30 10:56:23 +01:00
Jakub Chodorowicz
7247ffca2d feat: allow setting custom y axis range, even if points are outside of the range (#67533)
* feat: allow setting custom y axis range, even if points are outside of the range

* fix: adjust Waterfall null x value loki screenshot test
2025-12-30 09:15:10 +01:00
github-automation-metabase
8d7ffb6845 Update generated docs (master) (#67618)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-30 00:06:07 -05:00
Egor Grushin
2b97f841bc UXW-2597 fix row bar charts' tooltip (#67617)
* UXW-2597 fix Row Bar tooltip data error
2025-12-30 01:33:34 +00:00
Gabriel Moreno
fe7668963c UXW-69 Avoid persisting non-dashboard settings (#67592)
* fix: avoid persisting settings that are hidden from dashboard UI

* test: add `sanitizeDashcardSettings` unit spec

* refactor: use `_.pick` for sanitizing dashcard settings
2025-12-29 18:52:06 -04:00
bryan
29b1e70d21 fix perf/mapv to handle infinite and large lazy sequences (#66984) 2025-12-29 15:02:00 -07:00
Ryan Laurie
b8113ad526 Get personal collection hook (#66701)
* get personal collection hook

* use the hook

* better tests

* barrell

* Apply suggestions from code review

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>

* cmon claude

* review fixes

---------

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>
2025-12-29 14:42:33 -07:00
metamben
6d1cb34859 Normalize aggregation references, sort maps and remove all uuids (#67521)
* Normalize aggregation references, sort maps and remove all uuids

Fixes QUE-2916
2025-12-29 21:32:10 +00:00
Nemanja Glumac
0c2996b7da Re-introduce: Upload failed e2e test artifacts for quarantined tests (#67600) 2025-12-29 21:10:32 +00:00
Nathan Voxland
3d75754ad8 Added sucess and failure handling, general cleanup 2025-07-18 17:06:05 -05:00
Nathan Voxland
af72309d8e e2e test works again 2025-07-17 22:30:10 -05:00
Nathan Voxland
646b4c4548 Reverted metabase.queue changes, implemented metabase.queue.memory, code cleanup 2025-07-15 21:00:16 -05:00
Nathan Voxland
92ada9186c Code cleanup 2025-07-15 14:33:44 -05:00
Nathan Voxland
e67ce4582e Moved migrations 2025-07-14 23:07:20 -05:00
Nathan Voxland
25e3afcdbb Refactoring and trying to get e2e test to pass again 2025-07-14 23:07:20 -05:00
Nathan Voxland
b31a9a09c5 Configured queue listener to use persistent queue 2025-07-14 23:07:20 -05:00
Nathan Voxland
50614c15aa Initial implementation 2025-07-14 23:07:20 -05:00
9764 changed files with 940271 additions and 502723 deletions

View File

@@ -0,0 +1,12 @@
Generate a CI failure report for PR $PR_NUM_OR_URL (or current branch if no argument given).
Run `./bin/mage ci-report $PR_NUM_OR_URL` to generate the report, then:
1. **Summarize the failures** - What tests failed and in which jobs?
2. **Categorize** - Are these real failures, flaky tests, or infrastructure issues?
3. **Recommend next steps**:
- If flaky: suggest rerunning with `gh run rerun <run-id> --failed -R metabase/metabase`
- If real: identify the root cause and suggest fixes
- If infrastructure: note the issue type (timeout, OOM, network)
Focus on actionable insights. If all checks are passing, confirm that briefly.

View File

@@ -0,0 +1 @@
Run mutation testing for $ARGUMENTS

View File

@@ -12,14 +12,7 @@
## Testing
- **Run a test:** `./bin/mage run-tests namespace/test-name`
- **Run all tests in a namespace:** `./bin/mage run-tests namespace`
- **Run all tests for a module:** `./bin/mage run-tests test/metabase/notification` Because the module lives in that directory.
Note: the `./bin/mage run-tests` command accepts multiple args, so you can pass
`./bin/mage run-tests namespace/test-name namespace/other-test namespace/third-test`
to run 3 tests, or
`./bin/mage run-tests test/metabase/module1 test/metabase/module2` to run 2 modules.
Use `./bin/test-agent` to run backend tests. See the top-level CLAUDE.md for usage.
## Code Readability

View File

@@ -29,7 +29,7 @@ This guide covers Clojure and ClojureScript coding conventions for Metabase. See
**Comments:**
- `TODO` format: `;; TODO (Name M/D/YY) -- description`
- `TODO` format: `;; TODO (Name YYYY-MM-DD) -- description`
## Code Organization
@@ -42,7 +42,7 @@ This guide covers Clojure and ClojureScript coding conventions for Metabase. See
- Break up functions > 20 lines
- Lines ≤ 120 characters
- No blank lines within definition forms (except pairwise `let`/`cond`)
- No blank non-comment lines within definition forms (except pairwise `let`/`cond`)
## Style Conventions

View File

@@ -1,21 +1,21 @@
## Linting and Formatting
- **Lint:** `yarn lint-eslint-pure`
- **Lint:** `bun run lint-eslint-pure`
- Run ESLint on the codebase
- **Format:** `yarn prettier`
- **Format:** `bun run prettier`
- Format code using Prettier
- **Type Check:** `yarn type-check-pure`
- **Type Check:** `bun run type-check-pure`
- Run TypeScript type checking
## Testing
### JavaScript/TypeScript Tests
- **Test a specific file:** `yarn test-unit-keep-cljs path/to/file.unit.spec.js`
- **Test by pattern:** `yarn test-unit-keep-cljs -t "pattern"`
- **Test a specific file:** `bun run test-unit-keep-cljs path/to/file.unit.spec.js`
- **Test by pattern:** `bun run test-unit-keep-cljs -t "pattern"`
- Runs tests matching the given pattern
### ClojureScript Tests
- **Test ClojureScript:** `yarn test-cljs`
- **Test ClojureScript:** `bun run test-cljs`
- Run ClojureScript tests

View File

@@ -0,0 +1,357 @@
---
name: add-tracing
description: Add OpenTelemetry tracing spans to Clojure code following Metabase tracing conventions. Use when instrumenting backend code with trace coverage.
---
# Add Tracing Spans to Clojure Code
This skill helps you add OpenTelemetry (OTel) tracing spans to the Metabase backend codebase using the custom `tracing/with-span` macro.
## Reference Files
- `src/metabase/tracing/core.clj` - `with-span` macro, group registry, SDK lifecycle, `best-effort-sanitize-sql`, Pyroscope integration
- `src/metabase/task/impl.clj` - `defjob` macro that wraps Quartz jobs with root spans
- `.clj-kondo/config/modules/config.edn` - Module boundary configuration
## Module Architecture
The tracing module has a deliberately minimal API surface. **Only 2 namespaces are public** (listed in `:api` in the module config):
| Namespace | Role | Status |
|---|---|---|
| `tracing.core` | Primary API: `with-span`, groups, SDK lifecycle, Pyroscope, MDC, `best-effort-sanitize-sql` | **Public API** |
| `tracing.init` | Side-effect loader for `quartz` and `settings` | **Public API** (init convention) |
| `tracing.attributes` | `best-effort-sanitize-sql` implementation (re-exported via `tracing.core`) | Internal |
| `tracing.settings` | Setting definitions (`MB_TRACING_*` env vars) | Internal |
| `tracing.quartz` | Quartz JDBC proxy + JobListener | Internal |
**Rules:**
- Only require `[metabase.tracing.core :as tracing]` from outside the module. `tracing/best-effort-sanitize-sql` and all other public functions are available from this single namespace.
- Do not add new API namespaces. Add new public functions to `tracing.core` instead.
- Do not require internal namespaces (`tracing.attributes`, `tracing.settings`, `tracing.quartz`) from outside the module.
- `:uses :any` on the `core` module does NOT bypass the target module's `:api` check — internal namespaces are still enforced.
### Cyclic Dependency Avoidance
`tracing/core.clj` is required by many modules across the codebase. It **must NOT** compile-time require `tracing.settings`, as this creates transitive cyclic load dependencies (e.g., `settings/core -> tracing/settings -> tracing/core -> events/impl -> events/core`).
Instead, `tracing/core.clj` uses `requiring-resolve` for settings access:
```clojure
;; CORRECT — lazy runtime resolution, no compile-time dependency
((requiring-resolve 'metabase.tracing.settings/tracing-enabled))
;; WRONG — creates cyclic load dependency
(require '[metabase.tracing.settings :as settings])
(settings/tracing-enabled)
```
External library namespaces (clj-otel API, SDK, exporters) are safe to require normally — they don't participate in Metabase namespace cycles.
**Important:** `requiring-resolve` must use **literal quoted symbols**. Kondo hooks validate that `required-namespaces` are all simple symbols, so dynamic construction fails:
```clojure
;; CORRECT — literal quoted symbol
(requiring-resolve 'metabase.tracing.settings/tracing-endpoint)
;; WRONG — kondo hook rejects this: "Assert failed: (every? simple-symbol? required-namespaces)"
(requiring-resolve (symbol "metabase.tracing.settings" "tracing-endpoint"))
```
## Quick Checklist
When adding tracing spans:
- [ ] Module has `tracing` in its `:uses` set in `.clj-kondo/config/modules/config.edn`
- [ ] Added `[metabase.tracing.core :as tracing]` to ns requires (alphabetically sorted)
- [ ] Span wraps a meaningful I/O boundary (not pure computation)
- [ ] Group matches the domain (check `src/metabase/tracing/core.clj` for registered groups; add a new one if none fit)
- [ ] Span name follows dot-notation convention (`"domain.subsystem.operation"`)
- [ ] Attributes use namespaced keywords (`:search/query-length`, `:db/id`)
- [ ] No sensitive data in attributes (use `best-effort-sanitize-sql` for HoneySQL, never raw SQL)
- [ ] No new tracing namespaces created (add to `tracing.core` instead)
- [ ] No `DO_NOT_ADD_NEW_FILES_HERE.txt` violations in the target directory
- [ ] Run `clj-kondo --lint <files>` to verify 0 errors, 0 warnings
- [ ] Add or update tests in the corresponding `test/` path (see Testing section below)
- [ ] Run tests: `clojure -X:dev:test :only <test-ns>`
## The `with-span` Macro
```clojure
(tracing/with-span group span-name attrs & body)
```
- **group** - A keyword selecting which trace group this span belongs to (e.g., `:tasks`, `:sync`)
- **span-name** - A string identifying the span in traces (e.g., `"search.execute"`)
- **attrs** - A map of span attributes (e.g., `{:db/id 42}`)
- **body** - The code to execute inside the span
**When disabled:** zero overhead -- single atom deref + boolean check, body runs directly.
**When enabled:** creates OTel span AND injects `trace_id`/`span_id` into Log4j2 MDC for log-to-trace correlation.
## Trace Groups
Groups are registered in `src/metabase/tracing/core.clj`. Check that file for the current list. The general rule: **match the group to the domain, not the call site.** If code runs inside a Quartz job but is logically search work, use `:search`, not `:tasks`.
To add a new group:
```clojure
;; In src/metabase/tracing/core.clj
(register-group! :my-domain "Description of what this covers")
```
Users enable groups via `MB_TRACING_GROUPS=tasks,search,sync` (comma-separated, or `"all"`).
## Naming Conventions
### Span Names
Use dot-separated hierarchical names: `"domain.subsystem.operation"`. The domain prefix should match the group name:
```
search.execute -- `:search` group
sync.fingerprint.table -- `:sync` group
task.session-cleanup.delete -- `:tasks` group
db-app.collection-items -- `:db-app` group
```
### Attributes
Use namespaced keywords. The namespace groups related attributes:
```clojure
:db/id -- Database ID (integer)
:db/engine -- Database engine name (string)
:db/statement -- Sanitized SQL (string, via best-effort-sanitize-sql)
:search/engine -- Search engine name (string)
:search/query-length -- Query string length (integer)
:sync/table -- Table name (string)
:sync/step -- Sync step name (string)
:task/name -- Task name (string)
:http/method -- HTTP method (string)
:http/url -- Request URL (string)
```
Invent new namespaced attributes as needed (e.g., `:pulse/id`, `:transform/count`). Keep values as primitives (strings, numbers, booleans) -- no maps or collections.
## Step-by-Step: Adding a Span
### 1. Check module boundaries
Look up the module for your namespace in `.clj-kondo/config/modules/config.edn`. If `tracing` is not in the module's `:uses` set, add it (keep alphabetically sorted):
```edn
my-module
{:team "MyTeam"
:uses #{analytics config tracing util}}
```
### 2. Add the require
```clojure
(ns metabase.my-module.thing
(:require
[metabase.tracing.core :as tracing]
[metabase.util :as u]))
```
`best-effort-sanitize-sql` is available from `tracing.core` — no additional require needed.
### 3. Identify the I/O boundary
Only wrap code at **meaningful I/O boundaries**:
**DO trace:**
- External API calls (embedding APIs, metabot, webhooks)
- Database queries (both app DB and user DB)
- Network requests (HTTP calls to external services)
- Heavy batch processing (batch indexing, batch embedding)
- Top-level orchestration functions that coordinate multiple sub-operations
**DO NOT trace:**
- Pure computation (sorting, filtering, mapping)
- Simple single-row lookups (`t2/select-one :model/Setting :key k`)
- Every function in a call chain (only boundaries matter)
- Trivial operations (string formatting, hash calculations)
### 4. Wrap with `with-span`
```clojure
;; Simple span (no attributes needed)
(tracing/with-span :search "search.init-index" {}
(do-expensive-thing))
;; Span with static attributes
(tracing/with-span :sync "sync.fingerprint.table"
{:db/id (:db_id table)
:sync/table (:name table)}
(fingerprint-fields! table fields))
;; Span with computed attributes
(tracing/with-span :search "search.execute"
{:search/engine (name (:search-engine ctx))
:search/query-length (count (:search-string ctx))}
(search.engine/results ctx))
;; Span with sanitized SQL (for dynamic HoneySQL queries)
(let [hsql {:delete-from [(t2/table-name :model/Session)]
:where [:< :created_at oldest-allowed]}]
(tracing/with-span :tasks "task.session-cleanup.delete"
{:db/statement (tracing/best-effort-sanitize-sql hsql)}
(t2/query-one hsql)))
;; Sub-spans breaking a function into I/O phases
(let [embedding (tracing/with-span :search "search.semantic.embedding"
{:search.semantic/provider (:provider model)}
(get-embedding model search-string))
results (tracing/with-span :search "search.semantic.db-query" {}
(into [] xform reducible))]
(process results))
;; Per-item iteration spans
(doseq [e (search.engine/active-engines)]
(tracing/with-span :search "search.ingestion.update" {:search/engine (name e)}
(search.engine/update! e batch)))
```
### 5. Add tests
Create or update tests in the corresponding `test/` path. Follow the patterns in existing tracing tests:
- **Reference tests:** `test/metabase/tracing/quartz_test.clj`, `test/metabase/server/middleware/trace_test.clj`
- Use `tracing/init-enabled-groups!` / `tracing/shutdown-groups!` with `try`/`finally` to manage group lifecycle
- Test both enabled and disabled paths (verify zero overhead when group is off)
- Use `reify` mocks for Java interfaces (Connection, PreparedStatement, JobListener, etc.)
- Add `(set! *warn-on-reflection* true)` and type-hint proxy/reify calls to avoid reflection warnings
```clojure
(deftest my-span-enabled-test
(testing "when group is enabled, span is created"
(try
(tracing/init-enabled-groups! "my-group" "INFO")
;; ... test that span behavior occurs ...
(finally
(tracing/shutdown-groups!)))))
(deftest my-span-disabled-test
(testing "when group is disabled, code runs without tracing"
(tracing/shutdown-groups!)
;; ... test that code still works, no wrapping applied ...
))
```
### 6. Lint and run tests
```bash
# Lint modified source and test files — expect 0 errors, 0 warnings
clj-kondo --lint path/to/modified/file.clj path/to/test/file.clj
# Run tests (requires Java 21+)
clojure -X:dev:test :only my-ns.test-ns
```
Expect: all tests pass, 0 failures, 0 errors, no reflection warnings from your files.
## Sanitizing SQL for Attributes
When including SQL in span attributes, **always** use `tracing/best-effort-sanitize-sql`. This converts HoneySQL maps to parameterized SQL strings where values become `?` placeholders -- no data leaks.
```clojure
(let [hsql {:delete-from [:core_session]
:where [:< :created_at some-timestamp]}]
(tracing/with-span :tasks "task.cleanup.delete"
{:db/statement (tracing/best-effort-sanitize-sql hsql)}
(t2/query-one hsql)))
;; Trace attribute: db/statement = "DELETE FROM core_session WHERE created_at < ?"
```
**Rules:**
- Never put raw SQL strings or user-provided values in attributes
- Use `best-effort-sanitize-sql` only for app DB (HoneySQL) queries
- For external/user DB queries, trace only timing and counts, not SQL content
## Defjob and Root Spans
The `defjob` macro in `metabase.task.impl` automatically wraps every Quartz job with a `:tasks` root span:
```clojure
(task/defjob ^{DisallowConcurrentExecution true} SessionCleanup [_]
(cleanup-sessions!))
;; Automatically creates span: "task.SessionCleanup" {:task/name "SessionCleanup"}
```
You do NOT need a root span inside `defjob` bodies. Add **child spans** for I/O inside the job.
For code on plain `Thread`s (not Quartz), add the root span manually:
```clojure
(defn init! []
(tracing/with-span :search "search.task.init" {}
(search/init-index!)))
```
## What NOT to Do
### Span Usage Mistakes
```clojure
;; WRONG - pure computation, no I/O
(tracing/with-span :search "search.format-results" {}
(map format-result results))
;; WRONG - trivial single-row lookup
(tracing/with-span :db-app "db-app.get-setting" {}
(t2/select-one :model/Setting :key "my-setting"))
;; WRONG - raw SQL in attributes (data leak)
(tracing/with-span :tasks "task.cleanup" {:db/statement raw-sql-string}
(execute! raw-sql-string))
;; WRONG - wrong group (search work should use :search, not :tasks)
(tracing/with-span :tasks "search.execute" {} ...)
;; WRONG - redundant nesting (do-search already has a span)
(tracing/with-span :search "search.process" {}
(let [results (do-search ctx)]
(tracing/with-span :search "search.format" {}
(format-results results))))
```
### Architecture Mistakes
```clojure
;; WRONG - creating a new tracing namespace
(ns metabase.tracing.my-feature ...)
;; WRONG - requiring internal tracing namespaces from outside the module
(ns metabase.my-module.thing
(:require [metabase.tracing.attributes :as trace-attrs] ;; internal!
[metabase.tracing.settings :as tracing.settings] ;; internal!
[metabase.tracing.quartz :as tracing.quartz])) ;; internal!
;; WRONG - adding compile-time requires to tracing/core.clj for settings or SDK
;; This creates cyclic load dependencies because tracing/core is widely required
(ns metabase.tracing.core
(:require [metabase.tracing.settings :as settings])) ;; causes cycle!
;; WRONG - dynamic symbol construction with requiring-resolve (kondo rejects it)
(requiring-resolve (symbol "metabase.tracing.settings" "tracing-enabled"))
```
## Configuration
All settings are env-var-only (defined in `src/metabase/tracing/settings.clj`):
```bash
# Core
MB_TRACING_ENABLED=true # Enable tracing (default: false)
MB_TRACING_ENDPOINT=host:4317 # OTLP collector endpoint (default: http://localhost:4317)
MB_TRACING_GROUPS=tasks,search,sync # Comma-separated groups or "all" (default: all)
MB_TRACING_SERVICE_NAME=metabase # Service name in traces (default: hostname)
MB_TRACING_LOG_LEVEL=DEBUG # Log threshold for traced threads: TRACE/DEBUG/INFO (default: INFO)
# Batch span processor tuning
MB_TRACING_MAX_QUEUE_SIZE=2048 # Max spans queued for export; drops when full (default: 2048)
MB_TRACING_EXPORT_TIMEOUT_MS=10000 # Max wait for batch export to complete (default: 10000)
MB_TRACING_SCHEDULE_DELAY_MS=5000 # Delay between consecutive batch exports (default: 5000)
```

View File

@@ -0,0 +1,504 @@
---
name: analytics-events
description: Add product analytics events to track user interactions in the Metabase frontend
allowed-tools: Read, Write, Edit, Grep, Glob
---
# Frontend Analytics Events Skill
This skill helps you add product analytics (Snowplow) events to track user interactions in the Metabase frontend codebase.
## Quick Reference
Analytics events in Metabase use Snowplow with typed event schemas. All events must be defined in TypeScript types before use.
**Key Files:**
- `frontend/src/metabase-types/analytics/event.ts` - Event type definitions
- `frontend/src/metabase-types/analytics/schema.ts` - Schema registry
- `frontend/src/metabase/lib/analytics.ts` - Core tracking functions
- Feature-specific `analytics.ts` files - Tracking function wrappers
## Quick Checklist
When adding a new analytics event:
- [ ] Define event type in `frontend/src/metabase-types/analytics/event.ts`
- [ ] Add event to appropriate union type (e.g., `DataStudioEvent`, `SimpleEvent`)
- [ ] Create tracking function in feature's `analytics.ts` file
- [ ] Import and call tracking function at the interaction point
- [ ] Use `trackSimpleEvent()` for basic events (most common)
## Event Schema Types
### 1. Simple Events (Most Common)
Use `SimpleEventSchema` for straightforward tracking. It supports these standard fields:
```typescript
type SimpleEventSchema = {
event: string; // Required: Event name (snake_case)
target_id?: number | null; // Optional: ID of affected entity
triggered_from?: string | null; // Optional: UI location/context
duration_ms?: number | null; // Optional: Duration in milliseconds
result?: string | null; // Optional: Outcome (e.g., "success", "failure")
event_detail?: string | null; // Optional: Additional detail/variant
};
```
**When to use:** 90% of events fit this schema. Use for clicks, opens, closes, creates, deletes, etc.
### 2. Custom Schemas (legacy, no events are being added)
Consider adding new event schema only in very special cases.
**Examples:** `DashboardEventSchema`, `CleanupEventSchema`, `QuestionEventSchema`
## Step-by-Step: Adding a Simple Event
### Example: Track when a user applies filters in a table picker
#### Step 1: Define Event Types
Add event type definitions to `frontend/src/metabase-types/analytics/event.ts`:
```typescript
export type DataStudioTablePickerFiltersAppliedEvent = ValidateEvent<{
event: "data_studio_table_picker_filters_applied";
}>;
export type DataStudioTablePickerFiltersClearedEvent = ValidateEvent<{
event: "data_studio_table_picker_filters_cleared";
}>;
```
#### Step 2: Add to Union Type
Find or create the appropriate union type and add your events:
```typescript
export type DataStudioEvent =
| DataStudioLibraryCreatedEvent
| DataStudioTablePublishedEvent
| DataStudioGlossaryCreatedEvent
| DataStudioGlossaryEditedEvent
| DataStudioGlossaryDeletedEvent
| DataStudioTablePickerFiltersAppliedEvent // <- Add here
| DataStudioTablePickerFiltersClearedEvent; // <- Add here
```
#### Step 3: Create Tracking Functions
In your feature's `analytics.ts` file (e.g., `enterprise/frontend/src/metabase-enterprise/data-studio/analytics.ts`):
```typescript
import { trackSimpleEvent } from "metabase/lib/analytics";
export const trackDataStudioTablePickerFiltersApplied = () => {
trackSimpleEvent({
event: "data_studio_table_picker_filters_applied",
});
};
export const trackDataStudioTablePickerFiltersCleared = () => {
trackSimpleEvent({
event: "data_studio_table_picker_filters_cleared",
});
};
```
#### Step 4: Use in Components
Import and call the tracking function at the interaction point:
```typescript
import {
trackDataStudioTablePickerFiltersApplied,
trackDataStudioTablePickerFiltersCleared,
} from "metabase-enterprise/data-studio/analytics";
function FilterPopover({ filters, onSubmit }) {
const handleReset = () => {
trackDataStudioTablePickerFiltersCleared(); // <- Track here
onSubmit(emptyFilters);
};
return (
<form
onSubmit={(event) => {
event.preventDefault();
trackDataStudioTablePickerFiltersApplied(); // <- Track here
onSubmit(form);
}}
>
{/* form content */}
</form>
);
}
```
## Using SimpleEventSchema Fields
### Example: Event with target_id
```typescript
// Type definition
export type DataStudioLibraryCreatedEvent = ValidateEvent<{
event: "data_studio_library_created";
target_id: number | null;
}>;
// Tracking function
export const trackDataStudioLibraryCreated = (id: CollectionId) => {
trackSimpleEvent({
event: "data_studio_library_created",
target_id: Number(id),
});
};
// Usage
trackDataStudioLibraryCreated(newLibrary.id);
```
### Example: Event with triggered_from
```typescript
// Type definition
export type NewButtonClickedEvent = ValidateEvent<{
event: "new_button_clicked";
triggered_from: "app-bar" | "empty-collection";
}>;
// Tracking function
export const trackNewButtonClicked = (location: "app-bar" | "empty-collection") => {
trackSimpleEvent({
event: "new_button_clicked",
triggered_from: location,
});
};
// Usage
<Button onClick={() => {
trackNewButtonClicked("app-bar");
handleCreate();
}}>
New
</Button>
```
### Example: Event with event_detail
```typescript
// Type definition
export type MetadataEditEvent = ValidateEvent<{
event: "metadata_edited";
event_detail: "type_casting" | "semantic_type_change" | "visibility_change";
triggered_from: "admin" | "data_studio";
}>;
// Tracking function
export const trackMetadataChange = (
detail: "type_casting" | "semantic_type_change" | "visibility_change",
location: "admin" | "data_studio"
) => {
trackSimpleEvent({
event: "metadata_edited",
event_detail: detail,
triggered_from: location,
});
};
// Usage
trackMetadataChange("semantic_type_change", "data_studio");
```
### Example: Event with result and duration
```typescript
// Type definition
export type MoveToTrashEvent = ValidateEvent<{
event: "moved-to-trash";
target_id: number | null;
triggered_from: "collection" | "detail_page" | "cleanup_modal";
duration_ms: number | null;
result: "success" | "failure";
event_detail: "question" | "model" | "metric" | "dashboard";
}>;
// Tracking function
export const trackMoveToTrash = (params: {
targetId: number | null;
triggeredFrom: "collection" | "detail_page" | "cleanup_modal";
durationMs: number | null;
result: "success" | "failure";
itemType: "question" | "model" | "metric" | "dashboard";
}) => {
trackSimpleEvent({
event: "moved-to-trash",
target_id: params.targetId,
triggered_from: params.triggeredFrom,
duration_ms: params.durationMs,
result: params.result,
event_detail: params.itemType,
});
};
// Usage with timing
const startTime = Date.now();
try {
await moveToTrash(item);
trackMoveToTrash({
targetId: item.id,
triggeredFrom: "collection",
durationMs: Date.now() - startTime,
result: "success",
itemType: "question",
});
} catch (error) {
trackMoveToTrash({
targetId: item.id,
triggeredFrom: "collection",
durationMs: Date.now() - startTime,
result: "failure",
itemType: "question",
});
}
```
## Naming Conventions
### Event Names (snake_case)
```typescript
// Good
"data_studio_library_created"
"table_picker_filters_applied"
"metabot_chat_opened"
// Bad
"DataStudioLibraryCreated" // Wrong case
"tablePickerFiltersApplied" // Wrong case
"filters-applied" // Use underscore, not hyphen
```
### Event Type Names (PascalCase with "Event" suffix)
```typescript
// Good
DataStudioLibraryCreatedEvent
TablePickerFiltersAppliedEvent
MetabotChatOpenedEvent
// Bad
dataStudioLibraryCreated // Wrong case
DataStudioLibraryCreated // Missing "Event" suffix
```
### Tracking Function Names (camelCase with "track" prefix)
```typescript
// Good
trackDataStudioLibraryCreated
trackTablePickerFiltersApplied
trackMetabotChatOpened
// Bad
DataStudioLibraryCreated // Missing "track" prefix
track_library_created // Wrong case
logLibraryCreated // Use "track" prefix
```
## Common Patterns
### Pattern 1: Feature-Specific Union Types
Group related events together:
```typescript
export type DataStudioEvent =
| DataStudioLibraryCreatedEvent
| DataStudioTablePublishedEvent
| DataStudioGlossaryCreatedEvent;
export type MetabotEvent =
| MetabotChatOpenedEvent
| MetabotRequestSentEvent
| MetabotFixQueryClickedEvent;
// Then add to SimpleEvent union
export type SimpleEvent =
| /* other events */
| DataStudioEvent
| MetabotEvent
| /* more events */;
```
### Pattern 2: Conditional Tracking
Track different events based on user action:
```typescript
const handleSave = async () => {
if (isNewItem) {
await createItem(data);
trackItemCreated(newItem.id);
} else {
await updateItem(id, data);
trackItemUpdated(id);
}
};
```
## Common Pitfalls
### Don't: Add custom fields to SimpleEvent
```typescript
// WRONG - SimpleEvent doesn't support custom fields
export const trackFiltersApplied = (filters: FilterState) => {
trackSimpleEvent({
event: "filters_applied",
data_layer: filters.dataLayer, // ❌ Not in SimpleEventSchema
data_source: filters.dataSource, // ❌ Not in SimpleEventSchema
with_owner: filters.hasOwner, // ❌ Not in SimpleEventSchema
});
};
// RIGHT - Use only standard SimpleEventSchema fields
export const trackFiltersApplied = () => {
trackSimpleEvent({
event: "filters_applied",
});
};
// Or use event_detail for a single variant
export const trackFilterApplied = (filterType: string) => {
trackSimpleEvent({
event: "filter_applied",
event_detail: filterType, // ✓ "data_layer", "data_source", etc.
});
};
```
### Don't: Forget to add event to union type
```typescript
// Define the event
export type NewFeatureClickedEvent = ValidateEvent<{
event: "new_feature_clicked";
}>;
// ❌ WRONG - Forgot to add to SimpleEvent union
// Event won't be recognized by TypeScript
// ✓ RIGHT - Add to appropriate union
export type SimpleEvent =
| /* other events */
| NewFeatureClickedEvent;
```
### Don't: Mix up event name formats
```typescript
// WRONG
event: "dataStudioLibraryCreated" // camelCase
event: "data-studio-library-created" // kebab-case
event: "Data_Studio_Library_Created" // Mixed case
// RIGHT
event: "data_studio_library_created" // snake_case
```
### Don't: Track PII or sensitive data
```typescript
// WRONG - Don't track user emails, names, or sensitive data
trackSimpleEvent({
event: "user_logged_in",
event_detail: user.email, // ❌ PII
});
// RIGHT - Track non-sensitive identifiers only
trackSimpleEvent({
event: "user_logged_in",
target_id: user.id, // ✓ Just the ID
});
```
### Don't: Forget to track both success and failure
```typescript
// WRONG - Only tracking success
try {
await saveData();
trackDataSaved();
} catch (error) {
// ❌ No tracking for failure case
}
// RIGHT - Track both outcomes
try {
await saveData();
trackDataSaved({ result: "success" });
} catch (error) {
trackDataSaved({ result: "failure" });
}
```
## Testing Analytics Events
While developing, you can verify events are firing:
1. **Check browser console** - When `SNOWPLOW_ENABLED=true` in dev, events are logged
2. **Use shouldLogAnalytics** - Set in `metabase/env` to see all analytics in console
3. **Check Snowplow debugger** - Browser extension for Snowplow events
Example console output:
```
[SNOWPLOW EVENT | event sent:true], data_studio_table_picker_filters_applied
```
## File Organization
### Where to put tracking functions:
```
Feature-specific analytics functions:
frontend/src/metabase/{feature}/analytics.ts
enterprise/frontend/src/metabase-enterprise/{feature}/analytics.ts
Event type definitions (all in one place):
frontend/src/metabase-types/analytics/event.ts
Core tracking utilities:
frontend/src/metabase/lib/analytics.ts
```
## Real-World Examples
See these files for reference:
- **Simple events**: `enterprise/frontend/src/metabase-enterprise/data-studio/analytics.ts`
- **Events with variants**: `frontend/src/metabase/dashboard/analytics.ts`
- **Complex events**: `frontend/src/metabase/query_builder/analytics.js`
- **Event type examples**: `frontend/src/metabase-types/analytics/event.ts`
## Workflow Summary
1. **Identify the user interaction** to track
2. **Decide on event name** (snake_case, descriptive)
3. **Define event type** in `event.ts` using `ValidateEvent`
4. **Add to union type** (create feature union if needed)
5. **Create tracking function** in feature's `analytics.ts`
6. **Import and call** at the interaction point
7. **Test** that events fire correctly
## Tips
- **Be specific** - `filters_applied` is better than `action_performed`
- **Use past tense** - `library_created` not `create_library`
- **Group related events** - Create feature-specific event union types
- **Track meaningful actions** - Not every click needs tracking
- **Consider the data** - What would you want to analyze later?
- **Stay consistent** - Follow existing naming patterns in the codebase
- **Document context** - Use `triggered_from` to track where the action happened

View File

@@ -0,0 +1,173 @@
---
name: clojure-eval
description: Evaluate Clojure code via nREPL using clj-nrepl-eval. Use this when you need to test code, check if edited files compile, verify function behavior, or interact with a running REPL session.
---
# Clojure REPL Evaluation
## When to Use This Skill
Use this skill when you need to:
- **Verify that edited Clojure files compile and load correctly**
- Test function behavior interactively
- Check the current state of the REPL
- Debug code by evaluating expressions
- Require or load namespaces for testing
- Validate that code changes work before committing
## How It Works
The `clj-nrepl-eval` command evaluates Clojure code against an nREPL server. **Session state persists between evaluations**, so you can require a namespace in one evaluation and use it in subsequent calls. Each host:port combination maintains its own session file.
## Instructions
### 0. Discover and select nREPL server
First, discover what nREPL servers are running in the current directory:
```bash
clj-nrepl-eval --discover-ports
```
This will show all nREPL servers (Clojure, Babashka, shadow-cljs, etc.) running in the current project directory.
**Then use the AskUserQuestion tool:**
- **If ports are discovered:** Prompt user to select which nREPL port to use:
- **question:** "Which nREPL port would you like to use?"
- **header:** "nREPL Port"
- **options:** Present each discovered port as an option with:
- **label:** The port number
- **description:** The server type and status (e.g., "Clojure nREPL server in current directory")
- Include up to 4 discovered ports as options
- The user can select "Other" to enter a custom port number
- **If no ports are discovered:** Prompt user how to start an nREPL server:
- **question:** "No nREPL servers found. How would you like to start one?"
- **header:** "Start nREPL"
- **options:**
- **label:** "deps.edn alias", **description:** "Find and use an nREPL alias in deps.edn"
- **label:** "Leiningen", **description:** "Start nREPL using 'lein repl'"
- The user can select "Other" for alternative methods or if they already have a server running on a specific port
IMPORTANT: IF you start a REPL do not supply a port let the nREPL start and return the port that it was started on.
### 1. Evaluate Clojure Code
> Evaluation automatically connects to the given port
Use the `-p` flag to specify the port and pass your Clojure code.
**Recommended: Pass code as a command-line argument:**
```bash
clj-nrepl-eval -p <PORT> "(+ 1 2 3)"
```
**For multiple expressions (single line):**
```bash
clj-nrepl-eval -p <PORT> "(def x 10) (+ x 20)"
```
**Alternative: Using heredoc (may require permission approval for multiline commands):**
```bash
clj-nrepl-eval -p <PORT> <<'EOF'
(def x 10)
(+ x 20)
EOF
```
**Alternative: Via stdin pipe:**
```bash
echo "(+ 1 2 3)" | clj-nrepl-eval -p <PORT>
```
### 2. Display nREPL Sessions
**Discover all nREPL servers in current directory:**
```bash
clj-nrepl-eval --discover-ports
```
Shows all running nREPL servers in the current project directory, including their type (clj/bb/basilisp) and whether they match the current working directory.
**Check previously connected sessions:**
```bash
clj-nrepl-eval --connected-ports
```
Shows only connections you have made before (appears after first evaluation on a port).
### 3. Common Patterns
**Require a namespace (always use :reload to pick up changes):**
```bash
clj-nrepl-eval -p <PORT> "(require '[my.namespace :as ns] :reload)"
```
**Test a function after requiring:**
```bash
clj-nrepl-eval -p <PORT> "(ns/my-function arg1 arg2)"
```
**Check if a file compiles:**
```bash
clj-nrepl-eval -p <PORT> "(require 'my.namespace :reload)"
```
**Multiple expressions:**
```bash
clj-nrepl-eval -p <PORT> "(def x 10) (* x 2) (+ x 5)"
```
**Complex multiline code (using heredoc):**
```bash
clj-nrepl-eval -p <PORT> <<'EOF'
(def x 10)
(* x 2)
(+ x 5)
EOF
```
*Note: Heredoc syntax may require permission approval.*
**With custom timeout (in milliseconds):**
```bash
clj-nrepl-eval -p <PORT> --timeout 5000 "(long-running-fn)"
```
**Reset the session (clears all state):**
```bash
clj-nrepl-eval -p <PORT> --reset-session
clj-nrepl-eval -p <PORT> --reset-session "(def x 1)"
```
## Available Options
- `-p, --port PORT` - nREPL port (required)
- `-H, --host HOST` - nREPL host (default: 127.0.0.1)
- `-t, --timeout MILLISECONDS` - Timeout (default: 120000 = 2 minutes)
- `-r, --reset-session` - Reset the persistent nREPL session
- `-c, --connected-ports` - List previously connected nREPL sessions
- `-d, --discover-ports` - Discover nREPL servers in current directory
- `-h, --help` - Show help message
## Important Notes
- **Prefer command-line arguments:** Pass code as quoted strings: `clj-nrepl-eval -p <PORT> "(+ 1 2 3)"` - works with existing permissions
- **Heredoc for complex code:** Use heredoc (`<<'EOF' ... EOF`) for truly multiline code, but note it may require permission approval
- **Sessions persist:** State (vars, namespaces, loaded libraries) persists across invocations until the nREPL server restarts or `--reset-session` is used
- **Automatic delimiter repair:** The tool automatically repairs missing or mismatched parentheses
- **Always use :reload:** When requiring namespaces, use `:reload` to pick up recent changes
- **Default timeout:** 2 minutes (120000ms) - increase for long-running operations
- **Input precedence:** Command-line arguments take precedence over stdin
## Typical Workflow
1. Discover nREPL servers: `clj-nrepl-eval --discover-ports`
2. Use **AskUserQuestion** tool to prompt user to select a port
3. Require namespace:
```bash
clj-nrepl-eval -p <PORT> "(require '[my.ns :as ns] :reload)"
```
4. Test function:
```bash
clj-nrepl-eval -p <PORT> "(ns/my-fn ...)"
```
5. Iterate: Make changes, re-require with `:reload`, test again

View File

@@ -54,14 +54,14 @@ Use this to scan through changes efficiently:
- [ ] Public vars in `src` or `enterprise/backend/src` have useful docstrings
- [ ] Docstrings use Markdown conventions
- [ ] References use `[[other-var]]` not backticks
- [ ] `TODO` comments include author and date: `;; TODO (Name 1/1/25) -- description`
- [ ] `TODO` comments include author and date: `;; TODO (Name 2025-01-01) -- description`
### Code Organization
- [ ] Everything `^:private` unless used elsewhere
- [ ] No `declare` when avoidable (public functions near end)
- [ ] Functions under 20 lines when possible
- [ ] No blank lines within definition forms (except pairwise constructs in `let`/`cond`)
- [ ] No blank, non-comment lines within definition forms (except pairwise constructs in `let`/`cond`)
- [ ] Lines ≤ 120 characters
### Tests
@@ -118,7 +118,7 @@ Quick scan for common issues:
| `update-db`, `save-model` | Missing `!` for side effects: `update-db!`, `save-model!` |
| `snake_case_var` | Should use kebab-case |
| Public var without docstring | Add docstring explaining purpose |
| `;; TODO fix this` | Missing author/date: `;; TODO (Name 1/1/25) -- description` |
| `;; TODO fix this` | Missing author/date: `;; TODO (Name 2025-01-01) -- description` |
| `(defn foo ...)` in namespace used elsewhere | Should be `(defn ^:private foo ...)` |
| Function > 20 lines | Consider breaking up into smaller functions |
| `/api/dashboards/:id` | Use singular: `/api/dashboard/:id` |

View File

@@ -40,7 +40,7 @@ allowed-tools: Read, Write, Grep, Bash, Glob
**Format:**
- Run prettier on the file after making edits: `yarn prettier --write <file-path>`
- Run prettier on the file after making edits: `bun run prettier --write <file-path>`
- This ensures consistent formatting across all documentation
### Common patterns

View File

@@ -0,0 +1,260 @@
---
name: e2e-test-create
description: >
Analyze React component source code to understand UI structure,
then generate idiomatic Cypress E2E tests following Metabase conventions.
Falls back to Playwright MCP browser exploration only when code reading
and screenshot debugging are insufficient.
disable-model-invocation: true
allowed-tools:
- Bash
- Read
- Write
- Grep
- Glob
- Skill
- "mcp__playwright__*"
---
# Code-Reading-First → Generate Cypress Tests (Metabase)
You are writing Cypress E2E tests for the **Metabase** codebase.
Before generating ANY test code, you MUST analyze React component source code
to understand DOM structure, selectors, and user flows.
## Phase 0 — Research
1. Read existing helpers before writing anything:
- `e2e/support/helpers/` — all shared helpers (restore, signInAs, openOrdersTable, etc.)
- `e2e/support/cypress_sample_database.ts` — table/field schema constants (ORDERS, PRODUCTS, etc.)
- `e2e/support/cypress_sample_instance_data.ts` — instance-specific IDs (ORDERS_DASHBOARD_ID, NORMAL_USER_ID, etc.)
2. Glob `e2e/test/scenarios/` to find the closest existing spec to the area under test.
Study its patterns — match them exactly.
3. Glob `frontend/src/metabase/` to find React components for the feature area.
## Phase 1 — Code Analysis
Read React component source to understand DOM structure. No browser needed — source code has everything.
1. **Find relevant components**: Glob and grep `frontend/src/metabase/` for the feature area.
2. **Extract selectors**: Grep for `data-testid` in relevant components.
3. **Note visible text**: Read component JSX for button labels, headings, placeholders.
4. **Note aria attributes**: Grep for `aria-label` in relevant components.
5. **Understand user flows**: Read event handlers (onClick, onSubmit, onChange) to understand interactions.
6. **Find API calls**: Grep for `Api.use`, `fetch`, `useQuery`, endpoint definitions to identify API calls to intercept.
7. **Cross-reference with existing specs**: Find specs in the same area and reuse their proven selectors and `cy.intercept` patterns.
## Phase 2 — Start Backend
Use `MB_EDITION=oss` by default. Only use `MB_EDITION=ee` when the user explicitly asks to write an enterprise test.
Start the backend using `run_in_background: true` (NOT `&`).
`bin/e2e-backend` automatically detects if a backend is already running and reuses it.
```bash
MB_EDITION=oss bin/e2e-backend
```
Do NOT manually generate snapshots by running unrelated test specs.
The `bun test-cypress` runner has `GENERATE_SNAPSHOTS: true` by default and automatically
generates snapshots before running any spec. When running tests in Phase 4 via the `/e2e-test` skill,
snapshots will be generated on the first run if they don't already exist.
Restore clean test data:
```bash
curl -sf -X POST http://localhost:4000/api/testing/restore/default
```
## Phase 3 — Generate Cypress Spec
### File location & naming
Place specs in `e2e/test/scenarios/<area>/` mirroring the URL structure.
Name: `<feature>.cy.spec.js` (NOT `.cy.spec.ts`).
### Metabase conventions (mandatory)
- **Helpers via `cy.H`**: All helpers are accessed via `const { H } = cy;` — NOT via direct imports from `e2e/support/helpers`.
```js
const { H } = cy;
describe("feature name", () => {
beforeEach(() => {
H.restore();
cy.signInAsAdmin();
});
});
```
- **Sample Database schema** (table/field definitions): Import from `cypress_sample_database`.
```js
import { ORDERS, ORDERS_ID, PRODUCTS } from "e2e/support/cypress_sample_database";
```
- **Instance data** (dashboard IDs, user IDs, etc.): Import from `cypress_sample_instance_data`.
```js
import { ORDERS_DASHBOARD_ID } from "e2e/support/cypress_sample_instance_data";
```
- **Selectors** (priority order):
1. `cy.findByText()` / `cy.findByLabelText()` / `cy.findByRole()` — from `@testing-library/cypress`
2. `cy.findByTestId()` — for `data-testid` attributes
3. `cy.get("[data-testid='...']")` — fallback
4. NEVER use positional selectors, CSS class names, or XPaths.
- **Navigation helpers**: Use existing helpers like `H.openOrdersTable()`, `H.openNativeEditor()`,
`H.visitDashboard(id)`, `H.visitQuestion(id)` instead of raw `cy.visit()` chains.
Grep `e2e/support/helpers/` to discover what's available for your area.
- **API setup over UI setup**: Use `cy.request()` or existing API helpers to set up state.
Only use the UI for the flow you're actually testing.
- **Assertions**: Assert on visible text, URL, aria state — not DOM structure.
- **Waits**: Never use `cy.wait(ms)`. Use `cy.intercept()` + `cy.wait("@alias")` for API calls,
or `cy.findByText().should("be.visible")` for DOM readiness.
- **Isolation**: Each `it()` block must be independently runnable.
Don't depend on state from a previous `it()`.
### Spec structure template
```js
const { H } = cy;
import { ORDERS_DASHBOARD_ID } from "e2e/support/cypress_sample_instance_data";
import { ORDERS, ORDERS_ID } from "e2e/support/cypress_sample_database";
describe("area > sub-area > feature (#issue-number)", () => {
beforeEach(() => {
H.restore();
cy.signInAsAdmin();
});
it("should do the primary happy-path thing", () => {
// test
});
it("should handle the edge case", () => {
// test
});
});
```
### Intercepts
When you identified API calls during code analysis, stub or wait on them:
```js
cy.intercept("POST", "/api/dataset").as("dataset");
// ... trigger action ...
cy.wait("@dataset");
```
## Phase 4 — Validate
After generating specs:
1. Check that all imported helpers exist (Grep `e2e/support/helpers/`).
2. **You MUST use the `/e2e-test` skill** to run tests — do NOT run `bun test-cypress` directly.
The `/e2e-test` skill handles edition selection, snapshot management, and correct env vars.
`/e2e-test GREP="should do the thing" --spec e2e/test/scenarios/<path>`
If you created multiple `it()` blocks, run each one individually to isolate failures.
## Phase 5 — Fix Failures (up to 2 attempts)
When a test fails, **try to fix it from Cypress output first**:
1. Read the failure screenshot (path printed under `(Screenshots)`).
2. Read the error message and code frame from the console output.
3. Fix the test and re-run (back to Phase 4, step 2).
If you cannot diagnose the issue after 2 attempts, proceed to Phase 6.
## Phase 6 — Playwright Fallback
Only reach this phase after 2 failed fix attempts from Phase 5. The backend is already running.
Restore clean test data:
```bash
curl -sf -X POST http://localhost:4000/api/testing/restore/default
```
**Bypass CSP** headers before navigating (Metabase serves strict CSP that blocks dev server scripts).
Use `browser_run_code` to set this up:
```js
async (page) => {
// Strip CSP headers so the page loads (mirrors Cypress chromeWebSecurity: false)
await page.context().route('**/*', async (route) => {
const response = await route.fetch();
const headers = { ...response.headers() };
delete headers['content-security-policy'];
delete headers['content-security-policy-report-only'];
await route.fulfill({ response, headers });
});
// Sign in via API
const response = await page.request.post('http://localhost:4000/api/session', {
data: { username: 'admin@metabase.test', password: '12341234' }
});
const session = await response.json();
await page.context().addCookies([{
name: 'metabase.DEVICE',
value: session.id,
domain: 'localhost',
path: '/'
}]);
await page.goto('http://localhost:4000');
await page.waitForLoadState('networkidle');
return 'signed in';
}
```
**Maintain an observation log incrementally.** After EVERY significant Playwright interaction,
IMMEDIATELY append what you observed to the scratch file BEFORE performing the next interaction:
```bash
cat >> /tmp/e2e-observations.md << 'OBSERVATION'
## [Page/Flow name]
- URL: /question/notebook#...
- Clicked: "Box plot" button → visible text "Box plot", role: radio
- Selectors: data-testid="viz-type-button", findByText("Box plot")
- API call: POST /api/dataset (triggered on viz change)
- Key state: after selecting viz type, summary sidebar shows metric picker
OBSERVATION
```
For each page/flow:
- Take an accessibility snapshot (`browser_snapshot`).
- Click through interactive elements, fill forms, trigger modals.
- **Append to the observation log immediately after each step**: URLs, visible text, aria labels, `data-testid` attrs, API calls.
- Screenshot key states.
After exploration:
1. Read back your observation log: `cat /tmp/e2e-observations.md`
2. Fix the test using observed selectors and behavior.
3. Re-run the test (back to Phase 4).
4. Clean up: `rm -f /tmp/e2e-observations.md`
## Phase 7 — Cleanup
After all tests pass (or after giving up on fixing failures), **always kill the backend on port 4000**:
```bash
lsof -ti:4000 | xargs kill 2>/dev/null || true
```
Do NOT use broad `pkill` patterns — there may be other Metabase instances on different ports.
The backend process started in Phase 2 will NOT be killed automatically when the Claude session ends.
Leaving it running wastes resources and can interfere with future sessions. Always clean up.
## What NOT to do
- Do NOT use Playwright as the first step — always analyze source code first.
- Do NOT kill the backend between phases — it stays running throughout.
- Do NOT invent selectors you didn't find in source code or observe in the browser.
- Do NOT hardcode database IDs — import from `cypress_sample_database` or `cypress_sample_instance_data`.
- Do NOT use `cy.wait(1000)` or any numeric wait.
- Do NOT create setup flows through the UI when an API helper exists.
- Do NOT put tests in `cypress/e2e/` — Metabase uses `e2e/test/scenarios/`.
- Do NOT import helpers directly from `e2e/support/helpers` — use `const { H } = cy;`.

View File

@@ -0,0 +1,78 @@
---
name: e2e-test
description: Run Cypress E2E tests, analyze failures including screenshots, and stress test for flakiness
disable-model-invocation: false
---
Run Cypress E2E test: $ARGUMENTS
## Edition selection
**Default: `MB_EDITION=oss`** — runs without enterprise tokens, simpler and faster.
Only use `MB_EDITION=ee` when the user explicitly asks to write or run an enterprise test.
**For `MB_EDITION=ee`:**
These tokens must be exported in the shell before starting Claude Code:
- `CYPRESS_MB_ALL_FEATURES_TOKEN` — all features (most EE tests need this)
- `CYPRESS_MB_PRO_SELF_HOSTED_TOKEN` — pro self-hosted (permissions, SSO, sandboxing)
- `CYPRESS_MB_STARTER_CLOUD_TOKEN` — starter plan (rarely needed)
- `CYPRESS_MB_PRO_CLOUD_TOKEN` — pro cloud (rarely needed)
**NEVER echo, print, or log token values. Only check if they are set:**
```bash
echo "ALL_FEATURES: ${CYPRESS_MB_ALL_FEATURES_TOKEN:+set}" && echo "PRO_SELF_HOSTED: ${CYPRESS_MB_PRO_SELF_HOSTED_TOKEN:+set}" && echo "STARTER: ${CYPRESS_MB_STARTER_CLOUD_TOKEN:+set}" && echo "PRO_CLOUD: ${CYPRESS_MB_PRO_CLOUD_TOKEN:+set}"
```
If tokens are missing, tell the user: "EE tokens are not set. Either export them and restart Claude Code, or add `MB_EDITION=oss` to run OSS-only tests."
## Running
First check if snapshots exist:
```bash
ls e2e/snapshots/default.sql 2>/dev/null && echo "snapshots exist" || echo "snapshots missing"
```
If snapshots exist, skip regeneration for speed:
```bash
MB_EDITION=oss CYPRESS_VIDEO=false CYPRESS_RETRIES=0 CYPRESS_GUI=false GENERATE_SNAPSHOTS=false bun test-cypress $ARGUMENTS
```
If snapshots are missing (first run), let the runner generate them:
```bash
MB_EDITION=oss CYPRESS_VIDEO=false CYPRESS_RETRIES=0 CYPRESS_GUI=false bun test-cypress $ARGUMENTS
```
When running enterprise tests, replace `MB_EDITION=oss` with `MB_EDITION=ee` in the commands above.
If `$ARGUMENTS` is empty, ask the user which spec to run.
If the user provides a test name or fuzzy name instead of a spec path, find the spec file:
```bash
find e2e/test/scenarios -name "*FUZZY_NAME*.cy.spec.*" -type f
```
Then run with `--spec "path/to/matched.cy.spec.js"`.
To filter by test name, use the `GREP` env var (not `--env grep=`, which breaks on commas):
```bash
GREP="test name here" MB_EDITION=oss bun test-cypress --spec path/to/spec.js
```
## Stress test (flaky detection)
When the user asks to verify a test is not flaky:
```bash
MB_EDITION=oss bin/e2e-stress-test $ARGUMENTS
```
Set `E2E_STRESS_RUNS=N` for more iterations (default: 5). Stops on first failure and prints screenshot paths. Read those screenshots to analyze the failure.
## Analyzing failures
When tests fail:
1. Read the **screenshot** for each failure — paths are printed in Cypress output under `(Screenshots)`, typically at `cypress/screenshots/<spec-name>/<test-name> (failed).png`
2. Read the error message and code frame from the console output
3. Identify the root cause: is it a test bug, a product bug, or a timing issue?
4. Suggest a fix with specific code changes

View File

@@ -0,0 +1,834 @@
---
name: emotion-migrate
description: Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports from components.
---
# Emotion → Mantine + CSS Modules Migration Skill
Migrate Emotion styled-components (`@emotion/styled`, `@emotion/react`) to Mantine layout components with style props and CSS modules. The goal is zero Emotion imports, zero inline styles, and maximum use of design system tokens.
## Priority Order (Strict)
1. **Mantine components + style props** — `Box`, `Flex`, `Stack`, `Group`, `Text`, `Title`, `Card`. This is the DEFAULT. Every CSS property must be checked against style props FIRST.
2. **CSS modules** (`.module.css`) — ONLY for properties that Mantine style props genuinely cannot express: pseudo-selectors (`:hover`, `:focus`, `::before`), `box-shadow`, `border` shorthand, `animation`/`@keyframes`, complex selectors, `cursor`, `pointer-events`, `overflow`, `text-overflow`, `white-space`, `transition`.
3. **Inline styles ONLY for dynamic values** — `style={{ }}` is allowed only for truly dynamic runtime values (e.g., computed widths, positions, data-driven colors). All static styles must use Mantine props or CSS modules.
### Mantine-First Decision Gate (CRITICAL)
For EACH styled component, go through every CSS property and ask: "Can this be a Mantine style prop?" If yes → style prop. If no → CSS module. Do NOT dump an entire component into a CSS module just because one property needs it — split them.
**Properties that ARE style props** (use these, not CSS modules):
- `display` → `display` prop
- `color` → `c` prop (`c="brand"`, `c="text-primary"`)
- `background-color` → `bg` prop (`bg="background-primary"`)
- `font-size` → `fz` prop (`fz="md"`)
- `font-weight` → `fw` prop (`fw="bold"`)
- `line-height` → `lh` prop (`lh="md"`)
- `text-align` → `ta` prop (`ta="center"`)
- `padding` (all variants) → `p`, `px`, `py`, `pt`, `pb`, `pl`, `pr`
- `margin` (all variants) → `m`, `mx`, `my`, `mt`, `mb`, `ml`, `mr`
- `width` → `w`, `min-width` → `miw`, `max-width` → `maw`
- `height` → `h`, `min-height` → `mih`, `max-height` → `mah`
- `flex` → `flex` prop (`flex="0 0 auto"`, `flex={1}`)
- `gap` → `gap` prop (on Flex/Stack/Group)
- `align-items` → `align` prop (on Flex/Stack/Group)
- `justify-content` → `justify` prop (on Flex/Stack/Group)
- `flex-direction` → `direction` prop (on Flex)
- `flex-wrap` → `wrap` prop (on Flex)
- `position` → `pos` prop
- `top/right/bottom/left` → `top`, `right`, `bottom`, `left` props
- `opacity` → `opacity` prop
**Properties that NEED CSS modules** (no style prop equivalent):
- `:hover`, `:focus`, `:active`, `::before`, `::after` (pseudo-selectors)
- `box-shadow`, `border` (shorthand with color), `outline`
- `cursor`, `pointer-events`
- `overflow`, `text-overflow`, `white-space`
- `animation`, `transition`, `transform`
- `@media` queries (UNLESS it's simple responsive spacing/sizing — then use responsive syntax: `p={{ base: "md", lg: "xl" }}`)
**Hybrid approach** — when a component needs BOTH, put style props on the Mantine component AND add a CSS module class for the rest:
```tsx
<Flex
className={S.root} /* for :hover, box-shadow, border */
align="center" /* style prop */
gap="sm" /* style prop */
p="md" /* style prop */
bg="background-primary" /* style prop */
>
```
## CSS Module Conventions (Strict)
### Class Naming: camelCase
All CSS module class names MUST use **camelCase**. This is the dominant convention across the codebase (~830 camelCase vs ~620 PascalCase classes), used consistently in Mantine UI components, and matches standard CSS module conventions.
```css
/* CORRECT */
.root {
}
.settingsSection {
}
.dragHandle {
}
.closeIcon {
}
/* WRONG — do not use PascalCase or kebab-case */
.ItemRoot {
}
.settings-section {
}
```
Modifier/state classes also use camelCase:
```css
.selected {
}
.disabled {
}
.interactive {
}
.draggable {
}
```
### No Cascading — Direct Class Assignment
Cascading selectors are **discouraged**. Instead of styling through parent-child relationships, assign a class directly to the element that needs styling.
```css
/* WRONG — cascading/descendant selectors */
.root > input {
}
.root .label {
}
.container > div > span {
}
/* CORRECT — direct class on the target element */
.input {
}
.label {
}
.title {
}
```
The only acceptable nesting patterns are:
- **Pseudo-selectors on the same element**: `.item { &:hover { } }`
- **Modifier composition**: `.item { &.selected { } }`
- **Hover-reveal patterns** where a parent hover affects a child: `.root:hover .showOnHover { opacity: 1; }` — but only when structurally necessary (the child has no way to know about the parent's hover state)
### Import Alias
Always import the CSS module as `S`:
```tsx
import S from "./ComponentName.module.css";
```
## Step-by-Step Migration Process
### Step 1: Read and Understand
Read the `.styled.tsx` file AND every component that imports from it. Understand:
- Which styled components are used and where
- Which props drive dynamic styles
- Which styles are static vs conditional
- Which styles can map directly to Mantine style props
### Step 2: Classify Each Styled Component
For each styled component, apply the Mantine-First Decision Gate above. Then determine the migration target:
| Emotion Pattern | Migration Target |
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `styled.div` with only layout/spacing/color | `Box`, `Flex`, `Stack`, or `Group` with style props. **NO CSS module needed.** |
| `styled.div` with flexbox column | `Stack` component with style props |
| `styled.div` with flexbox row | `Flex` or `Group` component with style props |
| `styled.span` / `styled.p` with color/weight/size | **`Text component="span"` with style props** (`c`, `fw`, `fz`). NO CSS module. |
| `styled.div` with hover/focus/pseudo-selectors | **Hybrid**: Mantine component with style props for expressible properties + CSS module class for pseudo-selectors only |
| `styled.div` with media queries (simple spacing/sizing) | **Responsive style props**: `p={{ base: "md", lg: "xl" }}`. NO CSS module. |
| `styled.div` with media queries (complex/non-spacing) | CSS module for the media query parts, style props for the rest |
| `styled.div` with animations/keyframes | CSS module for animation, style props for layout |
| `styled(SomeComponent)` with only color/spacing/flex | **Wrap in Mantine component** with style props: `<Box c="brand" flex="0 0 auto"><Icon /></Box>`, or pass style props if the component accepts them |
| `styled(SomeComponent)` with pseudo-selectors/complex styles | CSS module `className` on the component |
| Dynamic props `styled.div<{ isActive: boolean }>` | Mantine style props for simple toggles (`c={active ? "brand" : "text-primary"}`), `cx()` with CSS module classes for complex state combinations involving pseudo-selectors |
### Step 3: Create CSS Module (if needed)
Create `ComponentName.module.css` alongside the component file:
```css
/* Use design system tokens — NEVER raw color/spacing values */
.root {
border: 1px solid var(--mb-color-border);
border-radius: var(--mantine-radius-md);
background-color: var(--mb-color-background-primary);
}
/* Conditional states as separate classes, combined with cx() */
.active {
background-color: var(--mb-color-brand);
color: var(--mb-color-text-primary-inverse);
}
.disabled {
color: var(--mb-color-text-tertiary);
pointer-events: none;
}
/* Hover/focus/pseudo-selectors — nest with & */
.interactive {
cursor: pointer;
&:hover {
color: var(--mb-color-brand);
background-color: var(--mb-color-background-hover);
}
}
/* Hover-reveal: acceptable parent→child nesting */
.root:hover .showOnHover {
opacity: 1;
}
/* Responsive styles */
@media (--breakpoint-min-md) {
.root {
padding: var(--mantine-spacing-lg);
}
}
```
### Step 4: Update the Component TSX
```tsx
import cx from "classnames";
import CS from "metabase/css/core/index.css";
import { Box, Flex, Group, Stack, Text } from "metabase/ui";
import S from "./ComponentName.module.css";
// Dynamic props → cx() with conditional classes
<Flex
className={cx(S.root, {
[S.active]: isActive,
[S.disabled]: disabled,
})}
align="center"
gap="sm"
p="md"
w="100%"
>
```
### Step 5: Delete the `.styled.tsx` File
Remove the old styled file entirely. Remove all imports of it from other files.
### Step 6: Verify
- Confirm zero `@emotion/styled` or `@emotion/react` imports remain in the migrated files
- Confirm no static inline styles (dynamic runtime values are fine)
- Confirm all colors use tokens, not raw hex/rgb values
## Design System Token Reference
### Mantine Style Props (use directly on components)
**Spacing** (`p`, `px`, `py`, `pt`, `pb`, `pl`, `pr`, `m`, `mx`, `my`, `mt`, `mb`, `ml`, `mr`):
- `"xs"` = 4px, `"sm"` = 8px, `"md"` = 16px, `"lg"` = 24px, `"xl"` = 32px
- Custom: `rem(48)` for non-standard values (import `rem` from `metabase/ui`)
**Dimensions** (`w`, `h`, `maw`, `mah`, `miw`, `mih`):
- `"100%"`, `"100vh"`, `rem(400)`, etc.
**Colors** (`c`, `bg`):
- Text: `"text-primary"`, `"text-secondary"`, `"text-tertiary"`
- Background: `"background-primary"`, `"background-secondary"`, `"background-hover"`
- Brand: `"brand"`, `"error"`, `"success"`, `"warning"`
**Typography** (`fz`, `fw`, `lh`, `ta`, `ff`):
- Font size: `"xs"` = 11px, `"sm"` = 12px, `"md"` = 14px, `"lg"` = 17px, `"xl"` = 21px
- Font weight: `"bold"`, `"normal"`, or numeric `700`
- Line height: `"xs"` = 100%, `"sm"` = 115%, `"md"` = 122%, `"lg"` = 138%, `"xl"` = 150%
- Text align: `"center"`, `"left"`, `"right"`
**Flexbox** (`align`, `justify`, `gap`, `direction`, `wrap`, `flex`):
- `align="center"`, `justify="space-between"`, `gap="sm"`, `direction="column"`, `wrap="nowrap"`
- `flex={1}`, `flex="0 0 auto"`
**Other**: `pos` (position), `display`
**Responsive syntax**: `px={{ base: "md", md: "lg", lg: rem(48) }}`
### CSS Variable Tokens (use in `.module.css` files)
**Colors** — `var(--mb-color-<name>)`:
- `--mb-color-text-primary`, `--mb-color-text-secondary`, `--mb-color-text-tertiary`
- `--mb-color-background-primary`, `--mb-color-background-secondary`, `--mb-color-background-hover`
- `--mb-color-border`, `--mb-color-border-strong`, `--mb-color-border-subtle`
- `--mb-color-brand`, `--mb-color-brand-hover`
- `--mb-color-error`, `--mb-color-success`, `--mb-color-warning`
- `--mb-color-shadow`, `--mb-color-focus`
- `--mb-color-accent0` through `--mb-color-accent7`
**Mantine spacing** — `var(--mantine-spacing-<size>)`:
- `--mantine-spacing-xs` (4px), `--mantine-spacing-sm` (8px), `--mantine-spacing-md` (16px), `--mantine-spacing-lg` (24px), `--mantine-spacing-xl` (32px)
**Mantine radius** — `var(--mantine-radius-<size>)`:
- `--mantine-radius-xs` (4px), `--mantine-radius-sm` (6px), `--mantine-radius-md` (8px), `--mantine-radius-xl` (40px)
**Mantine font sizes** — `var(--mantine-font-size-<size>)`:
- `--mantine-font-size-xs` (11px), `--mantine-font-size-sm` (12px), `--mantine-font-size-md` (14px), `--mantine-font-size-lg` (17px), `--mantine-font-size-xl` (21px)
**Breakpoints** (in `.module.css` files):
- `@media (--breakpoint-min-sm)` (40em / 640px)
- `@media (--breakpoint-min-md)` (60em / 960px)
- `@media (--breakpoint-min-lg)` (80em / 1280px)
- `@media (--breakpoint-min-xl)` (120em / 1920px)
- Also available: `--breakpoint-max-*` variants
### Snap Hardcoded Literals to Nearest Design Token (CRITICAL)
When migrating, **never carry over hardcoded `rem`/`px` values** from the original Emotion code. Instead, snap them to the nearest design system token. The original values were often arbitrary — the migration is an opportunity to align with the design system.
**Spacing** — snap to the nearest Mantine spacing token:
| Hardcoded value | Nearest token | Style prop | CSS variable |
| --------------------------------- | ------------- | ------------ | ------------------------------ |
| `0.125rem` (2px) | `2px` | `2` (number) | `2px` (keep literal, no token) |
| `0.2rem` (3.2px), `0.25rem` (4px) | **xs** (4px) | `"xs"` | `var(--mantine-spacing-xs)` |
| `0.5rem` (8px) | **sm** (8px) | `"sm"` | `var(--mantine-spacing-sm)` |
| `0.75rem` (12px) | between sm/md | `rem(12)` | `0.75rem` (no exact token) |
| `1rem` (16px) | **md** (16px) | `"md"` | `var(--mantine-spacing-md)` |
| `1.5rem` (24px) | **lg** (24px) | `"lg"` | `var(--mantine-spacing-lg)` |
| `2rem` (32px) | **xl** (32px) | `"xl"` | `var(--mantine-spacing-xl)` |
**Border radius** — snap to the nearest Mantine radius token:
| Hardcoded value | Nearest token | CSS variable |
| ---------------- | ----------------------------- | -------------------------- |
| `0.25rem` (4px) | **xs** (4px) | `var(--mantine-radius-xs)` |
| `0.375rem` (6px) | **sm** (6px) | `var(--mantine-radius-sm)` |
| `0.5rem` (8px) | **md** (8px) | `var(--mantine-radius-md)` |
| `1rem`+ (16px+) | **xl** (40px) or keep literal | `var(--mantine-radius-xl)` |
**Font sizes** — snap to the nearest Mantine font size token:
| Hardcoded value | Nearest token | Style prop | CSS variable |
| -------------------------------- | ------------- | ---------- | ----------------------------- |
| `0.6875rem` (11px) | **xs** (11px) | `fz="xs"` | `var(--mantine-font-size-xs)` |
| `0.75rem` (12px) | **sm** (12px) | `fz="sm"` | `var(--mantine-font-size-sm)` |
| `0.875rem` (14px), `1rem` (16px) | **md** (14px) | `fz="md"` | `var(--mantine-font-size-md)` |
| `1.063rem` (17px) | **lg** (17px) | `fz="lg"` | `var(--mantine-font-size-lg)` |
| `1.3rem` (21px) | **xl** (21px) | `fz="xl"` | `var(--mantine-font-size-xl)` |
**Rules:**
- If the hardcoded value is within ~2px of a token, use the token
- If it falls exactly between two tokens, prefer the smaller one (tighter is safer)
- If no token is close (e.g., `48px` spacing), use `rem(48)` for style props or the literal value in CSS modules
- This applies everywhere: style props, CSS module values, Icon `size` props, etc.
## Common Migration Patterns
### Pattern 1: Static Layout Container → Mantine Component
**Before:**
```tsx
// Component.styled.tsx
export const Container = styled.div`
display: flex;
align-items: center;
gap: 0.5rem;
padding: 1rem;
width: 100%;
`;
```
**After:**
```tsx
<Flex align="center" gap="sm" p="md" w="100%">
```
### Pattern 2: Vertical Stack → Stack Component
**Before:**
```tsx
export const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 2rem;
`;
```
**After:**
```tsx
<Stack gap="lg" p="xl">
```
### Pattern 3: Dynamic Props → cx() with CSS Module Classes
**Before:**
```tsx
export const Item = styled.div<{ isSelected: boolean; disabled: boolean }>`
color: ${(props) =>
props.disabled ? color("text-tertiary") : color("text-primary")};
background-color: ${(props) =>
props.isSelected ? color("brand") : "transparent"};
cursor: ${(props) => (props.disabled ? "default" : "pointer")};
&:hover {
color: ${(props) => !props.disabled && color("brand")};
}
`;
```
**After (CSS module):**
```css
/* Item.module.css */
.itemRoot {
color: var(--mb-color-text-primary);
cursor: pointer;
&:hover {
color: var(--mb-color-brand);
}
}
.selected {
background-color: var(--mb-color-brand);
}
.disabled {
color: var(--mb-color-text-tertiary);
cursor: default;
&:hover {
color: var(--mb-color-text-tertiary);
}
}
```
**After (TSX):**
```tsx
<Box
className={cx(S.itemRoot, {
[S.selected]: isSelected,
[S.disabled]: disabled,
})}
>
```
### Pattern 4: Extending a Component → Style Props First, CSS Module Only If Needed
When a styled component wraps another component, first check if the styles can be expressed as style props on a Mantine wrapper or on the component itself. Only use a CSS module when properties genuinely need it.
**Before:**
```tsx
export const CardIcon = styled(Icon)`
display: block;
flex: 0 0 auto;
color: var(--mb-color-brand);
`;
export const CardTitle = styled(Ellipsified)`
color: var(--mb-color-text-primary);
font-size: 1rem;
font-weight: bold;
margin-left: 1rem;
`;
```
**After — style props on Mantine wrapper (preferred when ALL properties are expressible):**
```tsx
<Box display="block" flex="0 0 auto" c="brand">
<Icon {...icon} />
</Box>
<Box c="text-primary" fz="md" fw="bold" ml="md">
<Ellipsified>{title}</Ellipsified>
</Box>
```
**After — CSS module (use only when component has pseudo-selectors or non-expressible styles):**
```css
.icon {
color: var(--mb-color-brand);
width: 1.5rem;
height: 1.5rem;
cursor: pointer;
&:hover {
color: var(--mb-color-brand-hover);
}
}
```
```tsx
<Icon className={S.icon} name="warning" />
```
### Pattern 4b: `styled.span` / `styled.p` with Text Styles → `Text` Component
**Before:**
```tsx
export const Label = styled.span`
color: var(--mb-color-text-secondary);
font-weight: bold;
`;
export const Title = styled.span`
color: var(--mb-color-text-primary);
font-size: 1rem;
font-weight: bold;
margin-left: 0.5rem;
`;
```
**After — `Text` component with style props (NO CSS module needed):**
```tsx
<Text component="span" c="text-secondary" fw="bold">
{label}
</Text>
<Text component="span" c="text-primary" fz="md" fw="bold" ml="sm">
{title}
</Text>
```
`Text` renders as `<p>` by default. Use `component="span"` to render inline. All color, typography, and spacing props work directly — no CSS module needed for pure text styling.
### Pattern 5: Keyframes Animation → CSS Module
**Before:**
```tsx
const spin = keyframes`
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
`;
export const Spinner = styled.div`
animation: ${spin} 1s infinite linear;
`;
```
**After (CSS module):**
```css
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.spinner {
animation: spin 1s infinite linear;
}
```
**After (TSX):**
```tsx
<Box className={S.spinner} />
```
### Pattern 6: color() Function → CSS Variables
| Emotion (JS) | CSS Module | Mantine Style Prop |
| ----------------------- | ------------------------------------------------------------ | --------------------------- |
| `color("brand")` | `var(--mb-color-brand)` | `c="brand"` or `bg="brand"` |
| `color("text-primary")` | `var(--mb-color-text-primary)` | `c="text-primary"` |
| `color("border")` | `var(--mb-color-border)` | N/A (use CSS module) |
| `alpha("brand", 0.2)` | `color-mix(in srgb, var(--mb-color-brand), transparent 80%)` | N/A (use CSS module) |
### Pattern 7: Responsive Spacing/Sizing → Responsive Style Props (NOT CSS Media Queries)
When a styled component only changes spacing, sizing, or other style-prop-expressible values at breakpoints, use Mantine's responsive syntax instead of CSS module media queries.
**Before:**
```tsx
export const CaptionRoot = styled.div`
margin-bottom: 1.5rem;
${breakpointMinExtraLarge} {
margin-bottom: 2rem;
}
`;
```
**After — responsive style prop (NO CSS module needed):**
```tsx
<Flex mb={{ base: "lg", xl: "xl" }}>
```
Breakpoint keys: `base` (default), `xs` (40em), `sm` (48em), `md` (60em), `lg` (80em), `xl` (120em).
Only use CSS module `@media` queries when the responsive change involves non-style-prop properties (e.g., `box-shadow`, `border`, `cursor` changes at breakpoints).
### Pattern 8: Dynamic Computed Styles → Inline Styles
Inline styles are allowed **only** for truly dynamic values computed at runtime (e.g., widths, positions, colors from data). Everything else must use Mantine style props or CSS modules.
**Before:**
```tsx
export const Bar = styled.div<{ width: number }>`
width: ${(props) => props.width}%;
`;
```
**After:**
```tsx
<Box style={{ width: `${width}%` }} />
```
### Pattern 9: Core CSS Utility Classes (Discouraged)
**Do NOT introduce new `CS` utility class usage.** Core CSS utilities (`CS` from `metabase/css/core/index.css`) are legacy and discouraged for new code. Prefer Mantine style props or CSS modules instead.
If existing code already uses `CS` classes and you're not migrating that specific code, leave them alone. But when migrating Emotion → Mantine, replace with the proper alternative:
| Instead of `CS.*` | Use |
| ------------------- | ------------------------------------------------------- |
| `CS.overflowHidden` | CSS module: `overflow: hidden` |
| `CS.cursorPointer` | CSS module: `cursor: pointer` |
| `CS.flex1` | Style prop: `flex={1}` |
| `CS.flexNoShrink` | Style prop: `flex="0 0 auto"` |
| `CS.textBrandHover` | CSS module: `&:hover { color: var(--mb-color-brand); }` |
### Pattern 10: Shared Emotion Styles Across Files → Shared CSS Module + cx()
When Emotion exports a shared `css` block (like `animationStyles`) imported by many files, create ONE CSS module with the shared keyframe and a reusable class, then compose via `cx()`.
**Before (Emotion — shared animation used by 13+ skeleton files):**
```tsx
// ChartSkeleton.styled.tsx — defines shared animation
const fadingKeyframes = keyframes`
0% { opacity: 0.0625; }
50% { opacity: 0.125; }
100% { opacity: 0.0625; }
`;
export const animationStyles = css`
opacity: 0.1;
animation: ${fadingKeyframes} 1.5s infinite;
`;
// AreaSkeleton.styled.tsx — consumes it
import { animationStyles } from ".../ChartSkeleton.styled";
export const SkeletonImage = styled.svg`
${animationStyles};
flex: 1 1 0;
margin-top: 1rem;
border-bottom: 1px solid currentColor;
`;
// BarSkeleton.styled.tsx — also consumes it
import { animationStyles } from ".../ChartSkeleton.styled";
export const SkeletonImage = styled.svg`
${animationStyles};
flex: 1 1 0;
margin-top: 1rem;
`;
```
**After — shared CSS module:**
```css
/* ChartSkeleton.module.css */
@keyframes fading {
0% {
opacity: 0.0625;
}
50% {
opacity: 0.125;
}
100% {
opacity: 0.0625;
}
}
.animated {
opacity: 0.1;
animation: fading 1.5s infinite;
}
```
**After — per-component CSS modules with own styles only:**
```css
/* AreaSkeleton.module.css */
.skeletonImage {
flex: 1 1 0;
margin-top: 1rem;
border-bottom: 1px solid currentColor;
}
```
```css
/* BarSkeleton.module.css */
.skeletonImage {
flex: 1 1 0;
margin-top: 1rem;
}
```
**After — component TSX uses cx() to compose:**
```tsx
// AreaSkeleton.tsx
import cx from "classnames";
import ChartSkeletonS from "../ChartSkeleton/ChartSkeleton.module.css";
import S from "./AreaSkeleton.module.css";
const AreaSkeleton = (): JSX.Element => {
return (
<svg
className={cx(ChartSkeletonS.animated, S.skeletonImage)}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 371 113"
preserveAspectRatio="none"
>
<path d="..." fill="currentColor" />
</svg>
);
};
```
The shared module owns the `@keyframes` and the `.animated` class. Each consumer composes it with its own module class via `cx()`. No duplication of the keyframe definition.
## Import Template
```tsx
import cx from "classnames"; // only if needed for conditional classes
import { Box, Flex, Group, Stack, Text, rem } from "metabase/ui";
import S from "./ComponentName.module.css"; // only if CSS module is needed
```
## Checklist Before Finishing
- [ ] **MANTINE-FIRST CHECK**: Every CSS property that has a style prop equivalent (`c`, `bg`, `p`, `m`, `fw`, `fz`, `flex`, `gap`, `align`, `w`, `h`, etc.) is expressed as a style prop, NOT in a CSS module
- [ ] `styled.span`/`styled.p` with only color/weight/size are replaced with `Text component="span"` + style props, NOT CSS module classes
- [ ] `styled.div` with only layout props are replaced with `Flex`/`Stack`/`Group`/`Box` + style props, NOT CSS module classes
- [ ] Responsive spacing/sizing uses responsive style props (`mb={{ base: "lg", xl: "xl" }}`), NOT CSS module `@media` queries
- [ ] CSS modules are used ONLY for: pseudo-selectors, box-shadow, border, cursor, overflow, animation, transition, transform, or complex selectors
- [ ] All `@emotion/styled` and `@emotion/react` imports removed from migrated files
- [ ] The `.styled.tsx` file is deleted
- [ ] All imports of the deleted styled file are updated
- [ ] No static inline styles — `style={{ }}` used only for truly dynamic runtime values
- [ ] All colors use design tokens (`c="brand"`, `var(--mb-color-brand)`), not raw hex/rgb
- [ ] All spacing uses design tokens (`p="md"`, `var(--mantine-spacing-md)`), not arbitrary px values — hardcoded `rem`/`px` literals snapped to the nearest token (see mapping table above)
- [ ] All border-radius values use radius tokens (`var(--mantine-radius-md)`), not hardcoded `0.5rem`
- [ ] All font sizes use font-size tokens (`fz="md"`, `var(--mantine-font-size-md)`), not hardcoded `1rem`
- [ ] Layout uses Mantine components (`Flex`, `Stack`, `Group`, `Box`, `Text`) not raw divs/spans with CSS
- [ ] All CSS module class names use camelCase
- [ ] No cascading/descendant selectors targeting raw elements — use direct class assignment instead
- [ ] Component renders identically to the original (visually verify if possible)
## Visual Verification with Screenshots (Optional — Only When Explicitly Asked)
When the user explicitly asks to create before/after screenshots, use the Playwright MCP tools to capture them. This is NOT done by default — only when requested.
Screenshots must be taken in **both light and dark mode** to verify token usage is correct in both themes.
### Switching Color Scheme via API
Toggle between light and dark mode using the Metabase settings API. Use Playwright's `browser_evaluate` or `browser_navigate` with fetch:
```js
// Switch to dark mode
await fetch("/api/setting/color-scheme", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ value: "dark" }),
});
// Switch to light mode
await fetch("/api/setting/color-scheme", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ value: "light" }),
});
```
After switching, reload the page for the theme to take effect.
### Process
For each state (**after** = migrated code, **before** = stashed original), capture screenshots in both themes at both viewport widths. This produces **8 screenshots total**.
1. **Take "after" screenshots first** (migrated code is already in place):
- Navigate to the page that renders the migrated components (`browser_navigate`)
- Wait for content to load (`browser_wait_for` with key text, or `textGone: "Loading..."`)
- Close the sidebar if it overlaps content on narrow viewports (`browser_click` the toggle button)
- **Light mode** (set `color-scheme` to `"light"` via API, reload):
- Desktop (1280x900): `after-light-desktop.png`
- Narrow (640x900), close sidebar: `after-light-narrow.png`
- **Dark mode** (set `color-scheme` to `"dark"` via API, reload):
- Desktop (1280x900): `after-dark-desktop.png`
- Narrow (640x900), close sidebar: `after-dark-narrow.png`
2. **Stash changes to capture "before" screenshots**:
- Run `git stash --include-untracked` to temporarily revert to the Emotion version
- Repeat the same 4 screenshots with `before-` prefix:
- `before-light-desktop.png`, `before-light-narrow.png`
- `before-dark-desktop.png`, `before-dark-narrow.png`
- Run `git stash pop` to restore the migrated code
3. **Restore the user's original color scheme** (set back to `"auto"` or whatever it was before).
4. **Display all 8 screenshots** using the `Read` tool so the user can visually compare before/after in both themes at both viewport sizes.
### Key Details
- Save screenshots in the repo root (they will be untracked — user can delete after review)
- The dev server must be running (typically `http://localhost:3000`)
- Use `browser_snapshot` to find element refs when you need to click buttons (e.g., sidebar toggle)
- The greeting text on the home page changes randomly on each load — this is expected, not a regression
- If the page being tested is not the home page, navigate to the correct URL that exercises the migrated components
- Dark mode screenshots are critical for verifying that CSS variable tokens (`var(--mb-color-*)`) are used correctly — hardcoded colors will look wrong in dark mode

View File

@@ -0,0 +1,114 @@
---
name: mutation-testing
description: Run mutation testing on a Clojure namespace, generate tests to kill surviving mutations, and open draft PRs with Linear issue tracking.
---
# Mutation Testing Skill
This skill runs mutation testing end-to-end: generates a coverage report, groups functions, shells out to `claude -p` to write tests, verifies mutations are killed, and creates draft PRs with Linear issues.
## Prerequisites
- A running nREPL connected to the Metabase dev environment
- `LINEAR_API_KEY` environment variable set with a valid Linear personal API key
- `gh` CLI authenticated with GitHub
- `claude` CLI available on PATH
## Reference Files
- `dev/src/dev/coverage.clj` — mutation testing engine (generates reports, runs mutations)
- `dev/src/dev/mutation_testing.clj` — orchestration, Linear API, PR helpers
## Invocation
The argument is a Clojure namespace, optionally followed by a base branch:
```
/mutation-testing metabase.lib.order-by
/mutation-testing metabase.lib.order-by --base-branch release-x.52.x
/mutation-testing metabase.lib.order-by --project-id abc-123
/mutation-testing metabase.lib.order-by --base-branch release-x.52.x --project-id abc-123
```
- `--base-branch`: defaults to the value in config (set via `set-config!`), or `"master"` if not configured.
- `--project-id`: if provided, issues are added to this existing Linear project instead of creating a new one.
## Steps
### 1. Parse arguments
Parse `$ARGUMENTS` to extract:
- **namespace** (required) — the first positional argument
- **`--base-branch`** (optional) — if present, the next argument is the base branch name
- **`--project-id`** (optional) — if present, the next argument is an existing Linear project ID
### 2. Load and configure
```clojure
(require '[dev.mutation-testing :as mut-test] :reload)
(require '[dev.coverage :as cov] :reload)
```
If this is the first invocation (or the REPL was restarted), set up the Linear team:
```clojure
(mut-test/list-teams!)
(mut-test/set-config! {:team-id "<id>"})
```
### 3. Run
```clojure
(mut-test/run! '<target-ns>)
;; Or with options:
(mut-test/run! '<target-ns> {:base-branch "release-x.52.x"})
(mut-test/run! '<target-ns> {:project-id "abc-123"})
(mut-test/run! '<target-ns> {:base-branch "release-x.52.x" :project-id "abc-123"})
```
Pass the opts map with `:base-branch` and/or `:project-id` if those flags were provided in the arguments.
This will:
1. Generate a baseline mutation testing report
2. Create a Linear project for the namespace
3. Group functions by coverage relationships
4. For each group: create branch → invoke Claude to write tests → verify → retry if needed → commit & push → create Linear issue → create draft PR
5. Print a summary with PR links
### 4. Handle failures
If a group fails mid-processing, `run!` catches the error and continues to the next group. To retry a single group manually:
```clojure
;; Get the parsed namespace info
(def parsed (mut-test/parse-namespace '<target-ns>))
;; Run coverage to get the data
(def coverage-results (cov/test-namespace (:target-ns parsed) [(:test-ns parsed)]))
;; Group and find the one you want
(def groups (mut-test/group-functions coverage-results))
;; Process just that group
(mut-test/process-group! parsed (nth groups <index>))
```
### 5. Verify the prompt (dry run)
To inspect what Claude will see without invoking it:
```clojure
(def parsed (mut-test/parse-namespace '<target-ns>))
(def coverage-results (cov/test-namespace (:target-ns parsed) [(:test-ns parsed)]))
(def groups (mut-test/group-functions coverage-results))
(println (mut-test/build-test-prompt
(merge (select-keys parsed [:target-ns :test-ns :source-path :test-path])
(select-keys (first groups) [:fn-names :mutations]))))
```
## Configuration
- **Team ID**: Set once per REPL session via `(mut-test/list-teams!)` and `(mut-test/set-config! {:team-id "..."})`
- **Project ID**: Set automatically when `run!` calls `create-project-for-namespace!`
- **Base Branch**: Defaults to `"master"`. Override via `(mut-test/set-config! {:base-branch "release-x.52.x"})` or pass `{:base-branch "..."}` as the second arg to `run!`
- **Project ID**: If set (via `set-config!` or `run!` opts), `run!` reuses the existing Linear project instead of creating a new one

View File

@@ -12,8 +12,9 @@ allowed-tools: Read, Grep, Bash, Glob
Review pull requests with a focus on:
- Readability and maintainability
- Appropriate test coverage
- Compliance with project coding standards and conventions
- Code quality and best practices
- Clear and correct JSDoc comments
- Type safety and proper TypeScript usage
- React best practices (when applicable)
- React best practices (when applicable)

View File

@@ -1,7 +1,7 @@
;; -*- comment-column: 100; -*-
{:config-paths ["macros" "src" "config"]
:linters
{ ;;
{;;
;; enabled optional linters (these are disabled by default)
;;
@@ -50,13 +50,15 @@
;; disabled linters
;;
:redundant-ignore {:level :off} ; lots of false positives, see https://github.com/clj-kondo/clj-kondo/issues/2414
:redundant-ignore {:level :off} ; lots of false positives, see https://github.com/clj-kondo/clj-kondo/issues/2414
:unexpected-recur {:level :off} ; TODO (cam): I think we just need to tell it how to handle MBQL match and we can enable this?
;;
;; globally-enabled custom linters
;;
:metabase/check-defmulti-arglists {:level :warning}
:metabase/check-def-check-not-uppercase-name {:level :warning}
:metabase/check-def-no-underscores {:level :warning}
:metabase/check-me-humanize {:level :warning}
:metabase/defsetting-must-specify-export {:level :warning}
:metabase/defsetting-namespace {:level :warning}
@@ -65,8 +67,8 @@
:metabase/missing-test-expr-requires-in-cljs {:level :warning}
:metabase/modules {:level :warning} ; more config in `.clj-kondo/config/modules/config.edn`
:metabase/namespace-name {:level :warning}
:metabase/no-jsqlparser-imports {:level :warning}
:metabase/require-shape-checker {:level :warning}
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn`
:metabase/tests-must-live-in-known-modules {:level :warning}
:metabase/validate-defendpoint-route-uses-kebab-case {:level :warning}
:metabase/validate-defendpoint-query-params-use-kebab-case {:level :warning}
@@ -174,10 +176,17 @@
clojure.core.async/to-chan!
clojure.core.async/to-chan!!
metabase.channel.core/send!
metabase.warehouses.models.database/assert-not-h2!
metabase.driver.sql-jdbc.execute/execute-prepared-statement!
metabase.notification.models/create-notification!
metabase.oauth-server.core/reset-provider!
metabase.pulse.send/send-pulse!
metabase-enterprise.transforms-python.python-runner-test/execute!
;; Workspace isolation functions are safe in parallel tests because they operate on
;; isolated, test-specific workspaces and databases that don't affect other tests
metabase-enterprise.workspaces.isolation/destroy-workspace-isolation!
metabase-enterprise.workspaces.isolation/ensure-database-isolation!
metabase-enterprise.workspaces.test-util/create-ready-ws!
;; Safe in tests, where we typically use a private, temporary index per thread.
metabase.search.core/reindex!
metabase.util/run-count!
@@ -191,7 +200,7 @@
:metabase/disallow-hardcoded-driver-names-in-tests
;; don't include `:h2` since that will probably lead to a mountain of tests where we are specifically testing
;; middleware or compilation behavior with just H2 since it's the default.
{:drivers #{ ;; core drivers
{:drivers #{;; core drivers
#_:h2
:postgres
:mysql
@@ -219,7 +228,10 @@
;; misc config for built-in linters
;;
:invalid-arity {:skip-args [metabase.lib.util.match/match]} ; TODO (cam): can we fix these?
:invalid-arity {:skip-args [metabase.lib.util.match/match
metabase.lib.util.match/match-lite
metabase.lib.util.match/match-many
metabase.lib.util.match/replace-lite]} ; TODO (cam): can we fix these?
:refer-all {:level :warning, :exclude [clojure.test]}
:unused-referred-var {:exclude {compojure.core [GET DELETE POST PUT]}}
@@ -238,13 +250,17 @@
(metabase.lib.util.match/match)
(metabase.lib.util.match/match-one)
(metabase.lib.util.match/match-lite)
(metabase.lib.util.match/match-lite-recursive)
(metabase.lib.util.match/match-many)
(metabase.lib.util.match/replace)
(metabase.lib.util.match/replace-in)
(metabase.lib.util.match/replace-lite)
(metabase.driver-api.core/match)
(metabase.driver-api.core/match-one)
(metabase.driver-api.core/match-lite)
(metabase.driver-api.core/match-many)
(metabase.driver-api.core/replace)
(metabase.driver-api.core/replace-in)
(metabase.driver-api.core/replace-lite)
(metabase.query-processor.middleware.cache-backend.interface/with-cached-results)
(metabase.util.regex/rx [opt])
(metabase.util/prog1 [<>])
@@ -296,10 +312,14 @@
metabase.lib.convert/->legacy-MBQL {:message "Conversion to legacy MBQL is discouraged, please use Lib to manipulate MBQL queries"}
metabase.lib.core/->legacy-MBQL {:message "Conversion to legacy MBQL is discouraged, please use Lib to manipulate MBQL queries"}
metabase.lib.equality/find-column-indexes-for-refs {:message "Use lib.equality/closest-matches-in-metadata or lib.equality/find-closest-matches-for-refs instead of lib.equality/find-column-indexes-for-refs"}
metabase.lib.util.match/match {:message "Use lib.util.match/match-many instead of lib.util.match/match."}
metabase.lib.util.match/match-one {:message "Use lib.util.match/match-lite instead of lib.util.match/match-one."}
metabase.lib.util.match/replace {:message "Use lib.util.match/replace-lite instead of lib.util.match/replace."}
metabase-enterprise.transforms.interface/execute! {:message "Use metabase-enterprise.transforms.execute/execute! instead of metabase-enterprise.transforms.interface/execute!"}
next.jdbc/active-tx? {:message "Use metabase.app-db.core/in-transaction? to see if we are in a transaction"}
toucan2.core/debug {:message "Don't commit code using t2/debug"}
toucan2.tools.debug/debug {:message "Don't commit code using t2/debug"}}
toucan2.tools.debug/debug {:message "Don't commit code using t2/debug"}
}
:discouraged-namespace
{camel-snake-kebab.core {:message "CSK is not Turkish-safe, use the versions in metabase.util instead."}
@@ -404,6 +424,8 @@
ring.util.codec codec
ring.util.response response
saml20-clj.core saml
metabase.transforms-base.util transforms-base.u
metabase.transforms.util transforms.u
toucan2.core t2}}}
:lint-as
@@ -418,11 +440,10 @@
metabase-enterprise.content-translation.routes-test/with-new-secret-key! clojure.core/fn
metabase-enterprise.serialization.test-util/with-dbs clojure.core/fn
metabase-enterprise.serialization.test-util/with-random-dump-dir clojure.core/let
metabase-enterprise.transforms.api-test/with-transform-tags clojure.core/let
metabase-enterprise.transforms.api-test/with-worker-runs clojure.core/let
metabase-enterprise.transforms.test-util/with-transform-cleanup! clojure.core/let
metabase-enterprise.transforms.execute/with-transform-lifecycle clojure.core/let
metabase-enterprise.workspaces.test-util/with-resources! clojure.core/let
metabase-enterprise.workspaces.test-util/with-workspaces! clojure.core/let
metabase.actions.test-util/with-actions clojure.core/let
metabase.transforms.test-util/with-transform-cleanup! clojure.core/let
metabase.api.common/let-404 clojure.core/let
metabase.app-db.custom-migrations.util/with-temp-scheduler! clojure.core/fn
metabase.app-db.custom-migrations/define-migration clj-kondo.lint-as/def-catch-all
@@ -510,7 +531,16 @@
{cljs.test/deftest hooks.clojure.test/deftest
cljs.test/is hooks.clojure.test/is
cljs.test/use-fixtures hooks.clojure.test/use-fixtures
clojure.core/def hooks.clojure.core.def/lint-def
clojure.core/definterface hooks.clojure.core.def/lint-def
clojure.core/defmacro hooks.clojure.core.defmacro/lint-defmacro
clojure.core/defmulti hooks.clojure.core.defmulti/lint-defmulti
clojure.core/defn hooks.clojure.core.defn/lint-defn
clojure.core/defn- hooks.clojure.core.defn/lint-defn
clojure.core/defonce hooks.clojure.core.def/lint-def
clojure.core/defprotocol hooks.clojure.core.def/lint-def
clojure.core/defrecord hooks.clojure.core.def/lint-def
clojure.core/deftype hooks.clojure.core.def/lint-def
clojure.core/ns hooks.clojure.core.ns/lint-ns
clojure.core/require hooks.clojure.core.require/lint-require
clojure.core/requiring-resolve hooks.clojure.core.require/lint-requiring-resolve
@@ -522,8 +552,11 @@
metabase-enterprise.advanced-permissions.models.permissions.application-permissions-test/with-new-group-and-current-graph hooks.common/with-two-top-level-bindings
metabase-enterprise.audit-app.pages-test/with-temp-objects hooks.common/with-one-binding
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
metabase-enterprise.dependencies.api-test/with-dependents-test! hooks.common/with-two-bindings
metabase-enterprise.metabot-v3.tools.dependencies-test/with-dependent-transforms! hooks.common/with-two-bindings
metabase-enterprise.metabot.tools.dependencies-test/with-dependent-transforms! hooks.common/with-two-bindings
metabase-enterprise.semantic-search.db.connection/with-migrate-tx hooks.common/let-one-with-optional-value
metabase-enterprise.serialization.api-test/with-serialization-test-data! hooks.common/with-three-bindings
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
metabase-enterprise.transforms-python.drivers-test/with-test-table hooks.common/with-two-bindings
metabase.api.common.internal-test/with-jetty-server hooks.common/with-one-binding
@@ -563,6 +596,9 @@
metabase.model-persistence.api-test/with-persistence-setup! hooks.common/with-one-top-level-binding
metabase.model-persistence.api-test/with-setup! hooks.common/with-one-top-level-binding
metabase.model-persistence.test-util/with-persistence-enabled! hooks.metabase.model-persistence.test-util/with-persistence-enabled!
metabase.mq.core/with-queue hooks.common/let-second
metabase.mq.core/with-topic hooks.common/let-second
metabase.mq.core/def-listener! hooks.metabase.mq.impl/def-listener
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.permissions.core/allow-changing-all-users-group-members hooks.common/do*
@@ -758,22 +794,17 @@
:config-in-ns
{test-namespaces
{:linters
{:inline-def {:level :off}
:missing-docstring {:level :off}
:private-call {:level :off}
:metabase/defsetting-must-specify-export {:level :off}
:metabase/defsetting-namespace {:level :off}
{:inline-def {:level :off}
:missing-docstring {:level :off}
:private-call {:level :off}
:metabase/defsetting-must-specify-export {:level :off}
:metabase/defsetting-namespace {:level :off}
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn`
:discouraged-var
{metabase.driver/database-supports? {:level :off}
metabase.lib.convert/->legacy-MBQL {:level :off}
metabase.lib.core/->legacy-MBQL {:level :off}}}
:hooks
{:analyze-call
{clojure.core/defmacro hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation
clojure.core/defn hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation
clojure.core/defn- hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation}}}
metabase.lib.core/->legacy-MBQL {:level :off}}}}
source-namespaces
{:linters

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
;; TODO -- seems silly to maintain different blacklists and whitelists here than we use for the deftest `^:parallel`
;; checker...
{:explicitly-safe
#{ ;; these toucan methods might actually set global values if it's used outside of a transaction,
#{;; these toucan methods might actually set global values if it's used outside of a transaction,
;; but since mt/with-temp runs in a transaction, so we'll ignore them in this case.
toucan2.core/delete!
toucan2.core/update!
@@ -110,6 +110,7 @@
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/log-deprecated-env-var-usage!
metabase.settings.models.setting/set!
metabase.settings.models.setting/validate-settings-formatting!
metabase.setup.core/create-token!

View File

@@ -1,9 +0,0 @@
(ns macros.metabase.server.statistics-handler-test)
(defmacro with-server
[_ _ [connector chan-start-handle chan-finish-handle chan-done-request] & body]
`(let [~connector nil
~chan-start-handle nil
~chan-finish-handle nil
~chan-done-request nil]
~@body))

View File

@@ -0,0 +1,38 @@
(ns hooks.clojure.core
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]))
(defn- all-uppercase? [symb]
(let [s (str symb)]
(= s #_{:clj-kondo/ignore [:discouraged-var]} (str/upper-case s))))
(defn- has-underscores? [symb]
(str/includes? (str symb) "_"))
(defn- check-symbol-is-kebab-case [symbol-node]
(let [symb (hooks/sexpr symbol-node)]
(when (or (all-uppercase? symb)
(has-underscores? symb))
(hooks/reg-finding! (assoc (meta symbol-node)
:message "Use kebab-case for function and variable names; don't use special notation for constants."
:type :metabase/check-def-kebab-case)))))
(defn lint-def* [{:keys [node]}]
(let [[_def & args] (:children node)
name-symbol (some (fn [arg]
(when (and (hooks/token-node? arg)
(symbol? (hooks/sexpr arg)))
arg))
args)]
(check-symbol-is-kebab-case name-symbol)))
(defn lint-def [x]
(lint-def* x)
x)
(comment
(defn x []
(let [node (-> "(def ^:private TYPE->MODEL {\"document\" :model/Document})"
hooks/parse-string)]
(lint-def {:node node}))))

View File

@@ -0,0 +1,52 @@
(ns hooks.clojure.core.def
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]))
(defn- uppercase-name?
"Whether the symbol is clearly an uppercase name like `TYPE-CONSTANTS` or `SOME_CONSTANT` or `TYPE->MODEL`."
[s]
(and (re-find #"[A-Z0-9]+(?:[-_]>?[A-Z0-9]+)+" s)
;; ignore stuff like `->SCREAMING_SNAKE_CASE`... this is ok
(not (str/includes? s "SCREAMING_SNAKE_CASE"))))
(defn- has-underscores? [s]
(and (str/includes? s "_")
;; ignore stuff like `->snake_case` and `->SCREAMING_SNAKE_CASE`
(not (str/includes? s "snake_case"))
(not (str/includes? s "SCREAMING_SNAKE_CASE"))))
(defn- check-symbol-is-kebab-case [symbol-node]
(let [symb (hooks/sexpr symbol-node)
s (str symb)]
(cond
(uppercase-name? s)
(hooks/reg-finding!
(assoc (meta symbol-node)
:message "Use lower-case names for functions and variables; don't use special notation for constants. [:metabase/check-def-check-not-all-uppercase]"
:type :metabase/check-def-check-not-uppercase-name))
(has-underscores? s)
(hooks/reg-finding!
(assoc (meta symbol-node)
:message "Use kebab-case names for functions and variables. [:metabase/check-def-no-underscores]"
:type :metabase/check-def-no-underscores)))))
(defn lint-def* [{:keys [node]}]
(let [[_def & args] (:children node)
name-symbol (some (fn [arg]
(when (and (hooks/token-node? arg)
(symbol? (hooks/sexpr arg)))
arg))
args)]
(check-symbol-is-kebab-case name-symbol)))
(defn lint-def [x]
(lint-def* x)
x)
(comment
(defn x []
(let [node (-> "(def ^:private TYPE->MODEL {\"document\" :model/Document})"
hooks/parse-string)]
(lint-def {:node node}))))

View File

@@ -0,0 +1,7 @@
(ns hooks.clojure.core.defmacro
(:require
[hooks.clojure.core.def]))
(defn lint-defmacro [x]
(hooks.clojure.core.def/lint-def* x)
x)

View File

@@ -2,6 +2,7 @@
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]
[hooks.clojure.core.def]
[hooks.common]))
(defn- check-arglists [report-node arglists]
@@ -49,4 +50,5 @@
(defn lint-defmulti [x]
(defmulti-check-for-arglists-metadata (:node x))
(hooks.clojure.core.def/lint-def* x)
x)

View File

@@ -2,6 +2,7 @@
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]
[hooks.clojure.core.def]
[hooks.common]))
(defn- end-with-exclamation?
@@ -50,6 +51,11 @@
(non-thread-safe-form-should-end-with-exclamation* node config))
{:node node})
(defn lint-defn [x]
(non-thread-safe-form-should-end-with-exclamation x)
(hooks.clojure.core.def/lint-def* x)
x)
(comment
(require '[clj-kondo.core :as clj-kondo])
(def form (str '(defmacro a

View File

@@ -99,12 +99,48 @@
:message "Metabase namespaces should have the form metabase[-enterprise].<module>.* [:metabase/namespace-name]"
:type :metabase/namespace-name)))))))
(defn- ns-form-node->import-node [ns-form-node]
(some (fn [node]
(when (and (hooks/list-node? node)
(let [first-child (first (:children node))]
(and (hooks/keyword-node? first-child)
(= (hooks/sexpr first-child) :import))))
node))
(:children ns-form-node)))
(defn- jsqlparser-import?
"Check if a symbol or string represents a jsqlparser import."
[s]
(str/starts-with? (str s) "net.sf.jsqlparser"))
(defn- lint-jsqlparser-imports [ns-form-node]
(when-let [import-node (ns-form-node->import-node ns-form-node)]
(doseq [node (rest (:children import-node))
:when (not (contains? (hooks.common/ignored-linters node) :metabase/no-jsqlparser-imports))]
(cond
;; Handle (net.sf.jsqlparser.foo Bar Baz) form
(hooks/list-node? node)
(let [package-node (first (:children node))
package-name (when package-node (str (hooks/sexpr package-node)))]
(when (jsqlparser-import? package-name)
(hooks/reg-finding! (assoc (meta node)
:message "Don't import net.sf.jsqlparser classes directly. This code should be agnostic to the parsing library. [:metabase/no-jsqlparser-imports]"
:type :metabase/no-jsqlparser-imports))))
;; Handle net.sf.jsqlparser.foo.Bar form (single class import)
(hooks/token-node? node)
(when (jsqlparser-import? (hooks/sexpr node))
(hooks/reg-finding! (assoc (meta node)
:message "Don't import net.sf.jsqlparser classes directly. This code should be agnostic to the parsing library. [:metabase/no-jsqlparser-imports]"
:type :metabase/no-jsqlparser-imports)))))))
(defn lint-ns [x]
(doto (:node x)
lint-require-shapes
lint-requires-on-new-lines
(lint-modules (modules/config x))
lint-namespace-name)
lint-namespace-name
lint-jsqlparser-imports)
x)
(comment

View File

@@ -31,7 +31,7 @@
second
symbol))))
(defn module-api-namespaces
(defn- module-api-namespaces
"Set of API namespace symbols for a given module. `:any` means you can use anything, there are no API namespaces for
this module (yet). If unspecified, the default is just the `<module>.core` namespace."
[config module]
@@ -51,6 +51,12 @@
(symbol (str ns-prefix ".core"))
(symbol (str ns-prefix ".init"))}))))
(defn- module-friends
[config module]
"Set of modules that are `:friends` of `module`, i.e. allowed to use *any* namespace from the module, not just the
designated [[module-api-namespaces]]."
(set (get-in config [:metabase/modules module :friends])))
(defn allowed-modules
"Set of namespace symbols that `module` is allowed to use. `:any` means it's allowed to use anything."
[config module]
@@ -61,11 +67,22 @@
(or (= allowed-modules :any)
(contains? (set allowed-modules) required-module))))
(defn allowed-module-namespace? [config ns-symb]
(defn- allowed-module-namespace? [config current-module ns-symb]
(let [module (module ns-symb)
module-api-namespaces (module-api-namespaces config module)]
module-api-namespaces (module-api-namespaces config module)
module-friends (module-friends config module)]
(or (empty? module-api-namespaces)
(contains? module-api-namespaces ns-symb))))
(contains? module-api-namespaces ns-symb)
(contains? module-friends current-module))))
(defn- rest-module? [module]
(str/ends-with? module "-rest"))
(defn- routes-module? [module]
(str/ends-with? module "-routes"))
(defn- core-module? [module]
(str/ends-with? module "core"))
(defn usage-error
"Find usage errors when a `required-namespace` is required in the `current-module`. Returns a string describing the
@@ -81,8 +98,19 @@
current-module
current-module)
(not (allowed-module-namespace? config required-namespace))
(not (allowed-module-namespace? config current-module required-namespace))
(format "Namespace %s is not an allowed external API namespace for the %s module. [:metabase/modules %s :api]"
required-namespace
required-module
required-module)))))
required-module)
;; (for now) rest modules are allowed to use one another; `routes` is ok because it collects routes together
;; and `core` is ok because [[metabase.core.init]] might need to init some of the `-routes` modules'
;; namespaces
(and (not ((some-fn rest-module? routes-module? core-module?) current-module))
(rest-module? required-module))
(format "Do not use -rest modules (%s) in non-rest modules (%s) -- move things from %s to %s if needed"
required-module
current-module
required-module
(symbol (str/replace required-module #"-rest$" "")))))))

View File

@@ -0,0 +1,24 @@
(ns hooks.metabase.mq.impl
(:require
[clj-kondo.hooks-api :as hooks]))
(defn def-listener
"Kondo hook for `mq/def-listener`. Rewrites to a `fn` form so kondo can analyze bindings.
Forms:
(mq/def-listener! :topic/foo [msg] body...)
(mq/def-listener! :queue/bar {:config map} [msgs] body...)"
[{:keys [node]}]
(let [[_ _channel-name & args] (:children node)
;; skip optional config map
args (if (hooks/map-node? (first args))
(rest args)
args)
[bindings & body] args
;; rewrite as: (fn [bindings...] body...)
new-node (hooks/list-node
(list*
(hooks/token-node 'fn)
bindings
body))]
{:node new-node}))

View File

@@ -55,7 +55,6 @@
help-link-custom-destination
instance-creation
is-hosted?
is-metabot-enabled
jdbc-data-warehouse-max-connection-pool-size
jdbc-data-warehouse-unreturned-connection-timeout-seconds
jwt-attribute-email

View File

@@ -43,6 +43,17 @@
'{:metabase/modules {api {:uses #{search}}
search {:api #{metabase.search.core}}}}))))
(deftest ^:parallel module-checker-friends-test
(is (= []
(lint-modules
'(ns metabase.search-rest.api
(:require
[metabase.search.config :as search.config]
[metabase.search.core :as search]))
'{:metabase/modules {search {:api #{metabase.search.core}
:friends #{search-rest}}
search-rest {:uses #{search}}}}))))
(deftest ^:parallel module-checker-api-namespaces-ignore-test
(is (empty? (lint-modules
'(ns metabase.api.search

View File

@@ -90,6 +90,7 @@
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-enterprise.workspaces.models.workspace-log/track! [[: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]]
@@ -119,7 +120,10 @@
metabase.dashboards.models.dashboard-test/with-dash-in-collection [[:inner 0]]
metabase.driver-api.core/match [[:inner 0]]
metabase.driver-api.core/match-one [[:inner 0]]
metabase.driver-api.core/match-lite [[:inner 0]]
metabase.driver-api.core/match-many [[:inner 0]]
metabase.driver-api.core/replace [[:inner 0]]
metabase.driver-api.core/replace-lite [[:inner 0]]
metabase.driver-api.core/replace-in [[:inner 0]]
metabase.driver.bigquery-cloud-sdk.query-processor/with-temporal-type [[:default]]
metabase.driver.druid.client/DELETE [[:default]]
@@ -133,6 +137,7 @@
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.driver/with-swapped-connection-details [[:block 2]]
metabase.embedding-rest.api.embed-test/do-response-formats [[:block 1]]
metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-temp-card-referencing [[:block 3]]
@@ -154,8 +159,9 @@
metabase.lib.util.match/match [[:inner 0]]
metabase.lib.util.match/match-one [[:inner 0]]
metabase.lib.util.match/match-lite [[:inner 0]]
metabase.lib.util.match/match-lite-recursive [[:inner 0]]
metabase.lib.util.match/match-many [[:inner 0]]
metabase.lib.util.match/replace [[:inner 0]]
metabase.lib.util.match/replace-lite [[:inner 0]]
metabase.lib.util.match/replace-in [[:inner 0]]
metabase.models.interface/define-batched-hydration-method [[:inner 0]]
metabase.models.interface/define-simple-hydration-method [[:inner 0]]
@@ -297,7 +303,6 @@
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/for-map [[:block 1]]

View File

@@ -1,23 +1,35 @@
Brite
afterAll
ags
altho
Brite
cancelation
cancelations
caracteres
copyin
datas
edn
eduction
hasTable
hasTables
horizontalX
horizontalY
juxt
methodd
nd
notIn
optionA
ot
pass-thru
requestor
re-use
re-used
ser
serieses
sortings
titel
trs
trsn
tru
trun
unparseable
withs

View File

@@ -1,3 +1,24 @@
[codespell]
skip = *.csv,*.edn,*.geojson,*.json,*.tsv,*.xml,docs/developers-guide/drivers/driver-tests.md,docs/developers-guide/e2e-tests.md,docs/questions/query-builder/expressions-list.md,docs/questions/visualizations/country-codes.md,e2e/test/scenarios/admin/i18n/content-translation/constants.ts,frontend/src/cljs,frontend/src/metabase/querying/expressions/tokenizer/lezer.js,frontend/src/metabase/static-viz/constants/char-sizes.ts,frontend/src/metabase/visualizations/lib/mapping_codes.ts,modules/drivers/mongo/src/metabase/driver/mongo/operators.clj
skip =
*.csv,
*.edn,
*.geojson,
*.json,
*.tsv,
*.unit.spec.*,
*.xml,
docs/developers-guide/drivers/driver-tests.md,
docs/developers-guide/e2e-tests.md,
docs/questions/query-builder/expressions-list.md,
docs/questions/visualizations/country-codes.md,
e2e/test/scenarios/admin/i18n/content-translation/constants.ts,
frontend/src/cljs,
frontend/src/metabase/querying/expressions/tokenizer/lezer.js,
frontend/src/metabase/query_builder/components/NativeQueryEditor/CodeMirrorEditor/language.ts,
frontend/src/metabase/static-viz/constants/char-sizes.ts,
frontend/src/metabase/visualizations/lib/mapping_codes.ts,
frontend/*/mocks/*,
modules/drivers/mongo/src/metabase/driver/mongo/operators.clj,
src/metabase/analyze/classifiers/name.clj,
src/metabase/util/currency.cljc,
ignore-words = .codespellignore

View File

@@ -1,10 +1,11 @@
FROM mcr.microsoft.com/vscode/devcontainers/java:21
# Set up nodesource, install node, yarn, fontconfig for static viz, rlwrap for dev ergonomics
# Set up nodesource, install node, bun, fontconfig for static viz, rlwrap for dev ergonomics
RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash ) \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig
&& apt-get update && apt-get -y install --no-install-recommends nodejs rlwrap fontconfig \
&& npm install -g bun
# install Clojure
RUN curl https://download.clojure.org/install/linux-install-1.12.0.1488.sh | bash

View File

@@ -61,6 +61,7 @@
(eval . (put-clojure-indent 'u/prog1 1))
(eval . (put-clojure-indent 'u/select-keys-when '(:form)))
(eval . (put-clojure-indent 'with-meta '(:form)))
(eval . (put-clojure-indent 'ws.log/track! 2))
;; these ones have to be done with `define-clojure-indent' for now because of upstream bug
;; https://github.com/clojure-emacs/clojure-mode/issues/600 once that's resolved we should use `put-clojure-indent'
;; instead. Please don't add new entries unless they don't work with `put-clojure-indent'

View File

@@ -100,7 +100,7 @@ METASTORE_DEV_SERVER_URL="https://token-check.staging.metabase.com"
#
# The whole environment is already orchestrated via deps.edn using :e2e alias.
# Treat it as a source of truth for JVM flags and ENVs whether you decide to run
# backend on your own, or using `yarn test-cypress` (local test runner).
# backend on your own, or using `bun run test-cypress` (local test runner).
#
# You don't _have to_ export any of these vars (except for the tokens below).
# Things will still work.
@@ -118,6 +118,9 @@ MB_EDITION="ee"
# MB_JETTY_HOST="localhost"
# MB_JETTY_PORT=4000
# Frontend dev server port (for hot reload). Must match the port used by `yarn build-hot`.
# MB_FRONTEND_DEV_PORT=8080
# 3.2 E2E Local Runner Setup
# ------------------------------------------------------------------------------

View File

@@ -1,6 +0,0 @@
frontend/src/cljs
frontend/src/cljs_release
e2e/support/cypress_sample_database.js
e2e/support/cypress_sample_instance_data.js
frontend/src/metabase-types/openapi/types.gen.ts
e2e/embedding-sdk-host-apps

View File

@@ -1,356 +0,0 @@
/* eslint-disable import/no-commonjs */
/* eslint-disable no-undef */
const path = require("path");
// `postcss-modules` lints css modules class names, but it currently crashes
// eslint on vscode. If you use webstorm or want to run the lint for the cli, you
// can use this flag to enable it. This is set to true in CI
const shouldLintCssModules =
process.env.LINT_CSS_MODULES === "true" || process.env.CI;
const plugins = ["react", "no-only-tests", "ttag", "i18next"];
if (shouldLintCssModules) {
plugins.push("postcss-modules");
}
module.exports = {
ignorePatterns: ["!.storybook"],
rules: {
strict: [2, "never"],
"no-undef": 2,
"no-var": 1,
"no-unused-vars": [
"error",
{
vars: "all",
args: "none",
varsIgnorePattern: "^_.+$",
ignoreRestSiblings: true,
},
],
"no-empty": [1, { allowEmptyCatch: true }],
// Note: adding this rule to a eslint config file in a subfolder will remove
// *not* carry over the restricted imports from parent folders, you will
// need to copy them over
"no-restricted-imports": [
"error",
{
paths: [
{
name: "moment",
message: "Moment is deprecated, please use dayjs",
},
{
name: "moment-timezone",
message: "Moment is deprecated, please use dayjs",
},
],
},
],
curly: [1, "all"],
eqeqeq: [1, "smart"],
"import/no-duplicates": ["warn", { considerQueryString: true }],
"import/no-default-export": 2,
"import/no-named-as-default": 0,
"import/no-commonjs": 1,
"import/order": [
"error",
{
"newlines-between": "always",
alphabetize: {
order: "asc",
orderImportKind: "asc",
caseInsensitive: false,
},
groups: [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
],
warnOnUnassignedImports: false,
},
],
"sort-imports": [
"error",
{
// allows this rule to work with import/order
ignoreDeclarationSort: true,
},
],
"no-console": [2, { allow: ["warn", "error", "errorBuffer"] }],
"react/no-is-mounted": 2,
"react/prefer-es6-class": 2,
"react/display-name": 1,
"react/prop-types": 2,
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 0,
"react/no-find-dom-node": 0,
"react/no-children-prop": 2,
"react/no-string-refs": 2,
"react/no-unescaped-entities": 2,
"react/jsx-no-target-blank": 2,
"react/jsx-key": 2,
"react/forbid-component-props": [2, { forbid: ["sx"] }],
"react-hooks/exhaustive-deps": ["warn"],
"prefer-const": [1, { destructuring: "all" }],
"no-restricted-globals": ["error", "close"],
"no-useless-escape": 0,
"no-only-tests/no-only-tests": [
"error",
{
block: [
"describe",
"it",
"context",
"test",
"tape",
"fixture",
"serial",
"Feature",
"Scenario",
"Given",
"And",
"When",
"Then",
],
},
],
complexity: ["error", { max: 55 }],
...(shouldLintCssModules
? {
"postcss-modules/no-undef-class": "error",
}
: {}),
},
globals: {
before: true,
cy: true,
Cypress: true,
},
env: {
browser: true,
es2020: true,
commonjs: true,
jest: true,
"jest/globals": true,
},
parser: "babel-eslint",
plugins,
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:depend/recommended",
"plugin:storybook/recommended",
"plugin:i18next/recommended",
],
settings: {
"import/internal-regex": "^metabase/|^metabase-lib/",
"import/resolver": {
webpack: {
config: path.resolve(__dirname, "./rspack.main.config.js"),
typescript: true,
},
},
"import/ignore": ["\\.css$"],
react: {
version: "detect",
},
"postcss-modules": {
baseDir: "./frontend/src",
},
},
parserOptions: {
ecmaFeatures: {
legacyDecorators: true,
},
},
overrides: [
{
files: ["*.js", "*.jsx", "*.ts", "*.tsx"],
rules: {
"jtag-missing-key": "error",
"no-unconditional-metabase-links-render": "error",
"no-color-literals": "error",
"no-literal-metabase-strings": "error",
"no-oss-reinitialize-import": "error",
"depend/ban-dependencies": [
"error",
{
allowed: [
"underscore",
"moment",
"lodash.orderby",
"lodash.debounce",
],
},
],
},
},
{
files: [
"*.unit.spec.*",
"frontend/src/metabase/admin/**/*",
"frontend/src/metabase/setup/**/*",
"enterprise/frontend/src/metabase-enterprise/whitelabel/**/*",
"enterprise/frontend/src/metabase-enterprise/embedding/**/*",
"frontend/lint/**/*",
"*.stories.*",
"**/.storybook/*",
"stories-data.*",
"e2e/**/*",
"**/tests/*",
"release/**/*",
"rspack.config.js",
"rspack.main.config.js",
"rspack.embedding-sdk-package.config.js",
"rspack.embedding-sdk-bundle.config.js",
],
rules: {
"no-color-literals": "off",
"no-unconditional-metabase-links-render": "off",
"no-literal-metabase-strings": "off",
},
},
{
files: [
"*.unit.spec.*",
"frontend/lint/**/*",
"*.stories.*",
"stories-data.*",
"e2e/**/*",
"**/tests/*",
"release/**/*",
"rspack.main.config.js",
],
rules: {
"i18next/no-literal-string": "off",
},
},
{
extends: ["plugin:@typescript-eslint/recommended"],
files: ["*.ts", "*.tsx"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
rules: {
"prefer-rest-params": "off",
"react/prop-types": "off", // TypeScript handles prop validation
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/consistent-type-imports": [
"error",
{
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_.+$",
varsIgnorePattern: "^_.+$",
ignoreRestSiblings: true,
destructuredArrayIgnorePattern: "^_.+$",
},
],
// This was introduced in 6.0.0
"@typescript-eslint/no-unsafe-declaration-merging": "off",
},
},
{
extends: [
"plugin:jest/recommended",
"plugin:jest-dom/recommended",
"plugin:testing-library/react",
"plugin:jest-formatting/recommended",
],
plugins: ["jest", "jest-dom", "testing-library", "jest-formatting"],
files: [
"*.unit.spec.ts",
"*.unit.spec.tsx",
"*.unit.spec.js",
"*.unit.spec.jsx",
],
rules: {
"jest/valid-title": ["error", { ignoreTypeOfDescribeName: true }],
"jest/expect-expect": [
"error",
{
assertFunctionNames: ["expect*", "assert*"],
additionalTestBlockFunctions: [],
},
],
},
},
{
// Enable jest formatting for cypress tests too, the plugin logic just works
extends: ["plugin:jest-formatting/recommended"],
files: ["*.cy.spec.ts", "*.cy.spec.js"],
},
{
files: ["frontend/src/**/*"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "Literal[value=/mb-base-color-/]",
message:
"You may not use base colors in the application, use semantic colors instead. (see colors.module.css)",
},
],
},
},
{
files: ["frontend/src/metabase/**/*"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "Literal[value=/mb-base-color-/]",
message:
"You may not use base colors in the application, use semantic colors instead. (see colors.module.css)",
},
],
},
},
{
files: ["frontend/src/metabase/query_builder/**/*"],
rules: {
"import/no-cycle": "error",
},
},
{
files: ["docs/**/snippets/**/*.{ts,tsx,js,jsx}"],
rules: {
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
"import/no-commonjs": "off",
"import/no-default-export": "off",
"import/order": "off",
"import/no-unresolved": "off",
"no-color-literals": "off",
},
},
{
files: ["frontend/build/**/*.js"],
rules: {
"import/no-commonjs": "off",
},
},
{
files: ["**/*.stories.tsx", "**/preview.tsx"],
rules: {
"import/no-default-export": "off",
},
},
],
};

8
.gitattributes vendored
View File

@@ -1,7 +1,9 @@
# Custom merge driver for YAML migration files
# Treats each changeset as an atomic unit to avoid conflicts within changesets
# Custom merge driver for per-release YAML migration files.
# Treats each changeset as an atomic unit to avoid conflicts within changesets.
# Only applies to per-release *_update_migrations.yaml files — directory-based
# migrations (e.g. 060/*.yaml) have one file per migration and don't need this.
# Execute this in your shell to enable custom merge driver:
# echo '\n[include]\npath=../.gitconfig' >> .git/config
#
# TODO (Bryan 12/12/25) -- reenable this when we can completely verify correctness
# resources/migrations/*.yaml merge=yaml-migrations
# resources/migrations/*_update_migrations.yaml merge=yaml-migrations

View File

@@ -1,7 +1,5 @@
# execute this in your shell to enable custom merge driver:
# echo '\n[include]\npath=../.gitconfig' >> .git/config
#
# TODO (Bryan 12/12/25) -- reenable this when we can completely verify correctness
# [merge "yaml-migrations"]
# name = YAML migration changeset-aware merge
# driver = mage -merge-yaml-migrations %O %A %B %L %P
[merge "yaml-migrations"]
name = Per-release YAML migration changeset-aware merge
driver = bin/mage -merge-yaml-migrations %O %A %B %L %P

268
.github/CODEOWNERS vendored
View File

@@ -1,266 +1,30 @@
# Before changing this file, make sure you have read how we use it:
# https://www.notion.so/metabase/Pull-Request-Code-Review-Guide-374f05df889748b69d67af753f9bc9b8?pvs=4#36550c04ceab40b5a8b8bee6264b090c
# @metabase/core-backend-querying-platform
src/metabase/lib @metabase/core-backend-querying-platform
src/metabase/lib_be @metabase/core-backend-querying-platform
src/metabase/query_processor @metabase/core-backend-querying-platform
# @metabase/graphy
src/metabase/graph @metabase/graphy
enterprise/backend/src/metabase_enterprise/dependencies @metabase/graphy
enterprise/frontend/src/metabase-enterprise/dependencies @metabase/graphy
# @metabase/embedding
enterprise/frontend/src/embedding-sdk-package @metabase/embedding
enterprise/frontend/src/embedding-sdk-bundle @metabase/embedding
enterprise/frontend/src/embedding-sdk-shared @metabase/embedding
frontend/src/metabase/embedding-sdk @metabase/embedding
frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion @metabase/embedding
frontend/src/metabase/public/containers/PublicOrEmbeddedDashboard @metabase/embedding
frontend/src/metabase/ui @metabase/core-frontend-ux-west
# snowplow/* @metabase/data
src/metabase/analytics/prometheus.clj @metabase/cloud-ops
.github @metabase/devexp
.clj-kondo @metabase/devexp
deps.edn @metabase/backend-developers
# @metabase/tech-writers
docs @metabase/tech-writers
docs/developers-guide # exclude from tech-writer ownership
#
# Backend modules <=> teams that own them
#
# @metabase/devexp
.github @metabase/devexp
# modules/drivers @metabase/drivers
src/metabase/driver/sql_jdbc/actions.clj @metabase/core-ux-east
test/metabase/driver/sql_jdbc/actions_test.clj @metabase/core-ux-east
# enterprise/backend/src/metabase_enterprise/advanced_config @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/advanced_config @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/advanced_permissions @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/advanced_permissions @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/airgap @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/airgap @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/api @metabase/devexp
# enterprise/backend/test/metabase_enterprise/api @metabase/devexp
# enterprise/backend/src/metabase_enterprise/audit_app @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/audit_app @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/auth_provider @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/auth_provider @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/billing @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/billing @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/cache @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/cache @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/content_verification @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/content_verification @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/core @metabase/devexp
# enterprise/backend/test/metabase_enterprise/core @metabase/devexp
# enterprise/backend/src/metabase_enterprise/dashboard_subscription_filters @metabase/core-ux-east
# enterprise/backend/test/metabase_enterprise/dashboard_subscription_filters @metabase/core-ux-east
# enterprise/backend/src/metabase_enterprise/enhancements @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/enhancements @metabase/core-backend-admin-webapp
# # enterprise/backend/src/metabase_enterprise/llm
# # enterprise/backend/test/metabase_enterprise/llm
# enterprise/backend/src/metabase_enterprise/query_reference_validation @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/query_reference_validation @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/sandbox @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/sandbox @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/scim @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/scim @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/search ...
# enterprise/backend/test/metabase_enterprise/search ...
# enterprise/backend/src/metabase_enterprise/serialization @metabase/core-ux-east
# enterprise/backend/test/metabase_enterprise/serialization @metabase/core-ux-east
# enterprise/backend/src/metabase_enterprise/snippet_collections @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/snippet_collections @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/sso @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/sso @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/stale @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/stale @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/stats @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/stats @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/task @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/task @metabase/core-backend-admin-webapp
# enterprise/backend/src/metabase_enterprise/upload_management @metabase/core-backend-admin-webapp
# enterprise/backend/test/metabase_enterprise/upload_management @metabase/core-backend-admin-webapp
src/metabase/actions @metabase/core-ux-east
test/metabase/actions @metabase/core-ux-east
# src/metabase/activity_feed @metabase/core-backend-admin-webapp
# test/metabase/activity_feed @metabase/core-backend-admin-webapp
# src/metabase/analytics @metabase/core-backend-admin-webapp
# test/metabase/analytics @metabase/core-backend-admin-webapp
# src/metabase/analyze @metabase/drivers
# test/metabase/analyze @metabase/drivers
# src/metabase/api @metabase/devexp
# test/metabase/api @metabase/devexp
# src/metabase/audit @metabase/core-backend-admin-webapp
# test/metabase/audit @metabase/core-backend-admin-webapp
# src/metabase/auth_provider @metabase/core-backend-admin-webapp
# test/metabase/auth_provider @metabase/core-backend-admin-webapp
# src/metabase/bookmarks @metabase/core-backend-admin-webapp
# test/metabase/bookmarks @metabase/core-backend-admin-webapp
# src/metabase/cmd @metabase/devexp
# test/metabase/cmd @metabase/devexp
# src/metabase/channel @metabase/core-ux-east
# test/metabase/channel @metabase/core-ux-east
# src/metabase/cloud_migration ...
# test/metabase/cloud_migration ...
# src/metabase/cmd @metabase/devexp
# test/metabase/cmd @metabase/devexp
# src/metabase/config @metabase/devexp
# test/metabase/config @metabase/devexp
# src/metabase/core @metabase/devexp
# test/metabase/core @metabase/devexp
# src/metabase/db @metabase/core-backend-admin-webapp
# test/metabase/db @metabase/core-backend-admin-webapp
# src/metabase/driver @metabase/drivers
# test/metabase/driver @metabase/drivers
# src/metabase/eid_translation @metabase/core-backend-admin-webapp
# test/metabase/eid_translation @metabase/core-backend-admin-webapp
# src/metabase/embed @metabase/embedding
# test/metabase/embed @metabase/embedding
# src/metabase/events @metabase/devexp
# test/metabase/events @metabase/devexp
# src/metabase/formatter @metabase/core-backend-querying
# test/metabase/formatter @metabase/core-backend-querying
# src/metabase/indexed_entities @metabase/core-backend-querying
# test/metabase/indexed_entities @metabase/core-backend-querying
# src/metabase/integrations ...
# test/metabase/integrations ...
# src/metabase/legacy_mbql @metabase/core-backend-querying
# test/metabase/legacy_mbql @metabase/core-backend-querying
# src/metabase/lib @metabase/core-backend-querying
# test/metabase/lib @metabase/core-backend-querying
# src/metabase/logger @metabase/devexp
# test/metabase/logger @metabase/devexp
# src/metabase/login_history @metabase/core-backend-admin-webapp
# test/metabase/login_history @metabase/core-backend-admin-webapp
# src/metabase/model_persistence @metabase/core-backend-querying
# test/metabase/model_persistence @metabase/core-backend-querying
# src/metabase/models @metabase/devexp
# test/metabase/models @metabase/devexp
# src/metabase/moderation @metabase/core-backend-admin-webapp
# test/metabase/moderation @metabase/core-backend-admin-webapp
# src/metabase/notification @metabase/core-ux-east
# test/metabase/notification @metabase/core-ux-east
# src/metabase/permissions @metabase/core-backend-admin-webapp
# test/metabase/permissions @metabase/core-backend-admin-webapp
# src/metabase/plugins @metabase/devexp
# test/metabase/plugins @metabase/devexp
# src/metabase/premium_features @metabase/core-backend-admin-webapp
# test/metabase/premium_features @metabase/core-backend-admin-webapp
# src/metabase/public_settings @metabase/core-backend-admin-webapp
# test/metabase/public_settings @metabase/core-backend-admin-webapp
# src/metabase/public_sharing @metabase/core-backend-admin-webapp
# test/metabase/public_sharing @metabase/core-backend-admin-webapp
# src/metabase/pulse @metabase/core-ux-east
# test/metabase/pulse @metabase/core-ux-east
# src/metabase/query_analysis @metabase/core-backend-querying
# test/metabase/query_analysis @metabase/core-backend-querying
# src/metabase/query_processor @metabase/core-backend-querying
# test/metabase/query_processor @metabase/core-backend-querying
# src/metabase/request @metabase/devexp
# test/metabase/request @metabase/devexp
# src/metabase/revisions @metabase/core-backend-admin-webapp
# test/metabase/revisions @metabase/core-backend-admin-webapp
# src/metabase/sample_data @metabase/core-backend-admin-webapp
# test/metabase/sample_data @metabase/core-backend-admin-webapp
# src/metabase/search ...
# test/metabase/search ...
# src/metabase/segments @metabase/core-backend-querying
# test/metabase/segments @metabase/core-backend-querying
# src/metabase/server @metabase/devexp
# test/metabase/server @metabase/devexp
# src/metabase/session @metabase/core-backend-admin-webapp
# test/metabase/session @metabase/core-backend-admin-webapp
# src/metabase/setup @metabase/core-backend-admin-webapp
# test/metabase/setup @metabase/core-backend-admin-webapp
# src/metabase/sso @metabase/core-backend-admin-webapp
# test/metabase/sso @metabase/core-backend-admin-webapp
# src/metabase/sync @metabase/drivers
# test/metabase/sync @metabase/drivers
# src/metabase/task @metabase/devexp
# test/metabase/task @metabase/devexp
# src/metabase/tiles @metabase/core-backend-dashviz
# test/metabase/tiles @metabase/core-backend-dashviz
# src/metabase/timeline @metabase/core-backend-dashviz
# test/metabase/timeline @metabase/core-backend-dashviz
# src/metabase/types @metabase/core-backend-querying
# test/metabase/types @metabase/core-backend-querying
# src/metabase/upload @metabase/core-backend-admin-webapp
# test/metabase/upload @metabase/core-backend-admin-webapp
# src/metabase/user_key_value @metabase/core-backend-admin-webapp
# test/metabase/user_key_value @metabase/core-backend-admin-webapp
# src/metabase/util @metabase/devexp
# test/metabase/util @metabase/devexp
# src/metabase/xrays @metabase/core-backend-querying
# test/metabase/xrays @metabase/core-backend-querying
# @metabase/cloud-ops
src/metabase/analytics/prometheus.clj @metabase/cloud-ops

View File

@@ -1,23 +0,0 @@
---
name: Epic (Internal Use)
about: This issue is used to track a feature/project that may span several days
to weeks to implement. This is used by the core Metabase team to project plan
and manage work.
title: "[Epic] Title"
labels: ".Epic"
---
### Links
- [product doc](LINK_TO_PRODUCT_DOC)
- [technical design doc](LINK_TO_TECHNICAL_DESIGN_DOC)
- [testing plan](LINK_TO_TESTING_PLAN)
- feature branch: `BRANCH_NAME`
- issue links: _related issues, if any_
### Implementation Plan
```[tasklist]
#### Milestone 1
- [ ] _Add tasks here_
```

View File

@@ -7,16 +7,13 @@ assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**What problem will this feature request solve?**
**Describe the solution you'd like**
**Describe the solution you'd like.**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**How does this feature request impact you?**
For example, is it a minor inconvenience, or does it block important work?
**How important is this feature to you?**
**Additional context**
**Additional information**
Add any other context or screenshots about the feature request here.

View File

@@ -1,14 +0,0 @@
---
name: Task (Internal Use)
about: This issue is used to track a smaller feature/task that does not require
being broken down to milestones. This is used by the core Metabase team to
project plan and manage work.
labels: ".Task"
---
**Context**
- issue links: _related issues if any_

View File

@@ -25,3 +25,4 @@ _Upload a demo video or before/after screenshots if sensible or remove the secti
### Checklist
- [ ] Tests have been added/updated to cover changes in this PR
- [ ] If adding new Loki tests: they pass [stress testing](https://github.com/metabase/metabase/actions/workflows/loki-stress-test-flake-fix.yml)

View File

@@ -5,7 +5,7 @@ PENDING CI / PENDING REVIEW / READY _(choose one and update accordingly)_
- Reproduces #XXXXX
### How to test this manually?
- `yarn test-cypress`
- `bun run test-cypress`
- `relative/path/to/the/file`
> _(For still unfixed bug)_
- Replace `it.skip()` with `it.only()` to run the test in isolation

View File

@@ -2,9 +2,16 @@ name: Fetch artifact
description: Fetches a specific artifact and downloads it to the current directory
inputs:
name:
description: The name of the artifact to fetch
commit:
description: Commit SHA for the artifact
required: true
edition:
description: Metabase edition (ee or oss)
required: true
release:
description: Whether this is a release artifact (uses metabase-release- prefix)
required: false
default: "false"
output-name:
description: Optional custom name for the output jar file (defaults to metabase.jar)
required: false
@@ -25,25 +32,44 @@ runs:
script: | # js
const fs = require('fs');
const isRelease = "${{ inputs.release }}" === "true";
const prefix = isRelease ? "metabase-release" : "metabase";
const artifactName = `${prefix}-${{ inputs.edition }}-${{ inputs.commit }}-uberjar`;
console.log(`Looking for artifact: ${artifactName}`);
const artifacts = await github.rest.actions.listArtifactsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
name: "${{ inputs.name }}",
name: artifactName,
per_page: 1,
});
if (!artifacts.data?.artifacts?.[0]?.id) {
throw new Error(`No artifacts found for ${{ inputs.name }}`);
core.setFailed(`No artifacts found for ${artifactName}`);
return;
}
const artifact_id = artifacts.data.artifacts[0].id;
const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact_id,
archive_format: 'zip',
});
let download;
const maxAttempts = 3;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact_id,
archive_format: 'zip',
});
break;
} catch (err) {
console.log(`Attempt ${attempt}/${maxAttempts} failed: ${err.message}`);
if (attempt === maxAttempts) throw err;
const delay = attempt * 15000; // 15s, 30s
console.log(`Retrying in ${delay / 1000}s...`);
await new Promise(r => setTimeout(r, delay));
}
}
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/mb.zip`, Buffer.from(download.data));

View File

@@ -7,9 +7,15 @@ outputs:
m2-cache-key:
description: "The cache key for the Maven cache."
value: ${{ steps.keys-factory.outputs.m2-cache-key }}
m2-restore-key:
description: "The fallback restore key prefix for the Maven cache."
value: ${{ steps.keys-factory.outputs.m2-restore-key }}
node-cache-key:
description: "The cache key for the Node.js cache."
value: ${{ steps.keys-factory.outputs.node-cache-key }}
node-restore-key:
description: "The fallback restore key prefix for the Node.js cache."
value: ${{ steps.keys-factory.outputs.node-restore-key }}
eslint-cache-key:
description: "The cache key for Eslint cache"
value: ${{ steps.keys-factory.outputs.eslint-cache-key }}
@@ -31,7 +37,9 @@ runs:
CACHE_SUFFIX="${{ runner.os }}-$WEEK_OF_YEAR"
echo "m2-cache-key=$M2_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
echo "m2-restore-key=$M2_CACHE_PREFIX-" >> $GITHUB_OUTPUT
echo "node-cache-key=$NODE_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
echo "node-restore-key=$NODE_CACHE_PREFIX-" >> $GITHUB_OUTPUT
echo "eslint-cache-key=$ESLINT_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
echo "cypress-cache-key=$CYPRESS_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
shell: bash

View File

@@ -0,0 +1,19 @@
name: Maximize disk space
description: Removes unused stuff from GH runner
runs:
using: "composite"
steps:
- name: Maximize build space
shell: bash
run: |
echo "-- Dotnet"
sudo rm -rf /usr/share/dotnet
echo "-- Android"
sudo rm -rf /usr/local/lib/android
echo "-- Haskell"
sudo rm -rf /opt/ghc
echo "-- CodeQL"
sudo rm -rf /opt/hostedtoolcache/CodeQL
df -h

View File

@@ -1,14 +1,13 @@
name: Prepare back-end environment
description: |
Prepare the backend. Installs jdk, Clojure, and fetches the cache for m2.
The CI config fetches `ci-test-config.json` from master and lets us ignore tests at the var level if they are flaking.
inputs:
java-version:
required: true
default: '21'
default: "21"
clojure-version:
required: true
default: '1.12.0.1488'
default: "1.12.0.1488"
runs:
using: "composite"
@@ -17,18 +16,33 @@ runs:
uses: actions/setup-java@v4
with:
java-version: ${{ inputs.java-version }}
distribution: 'temurin'
distribution: "temurin"
- name: Install Clojure CLI
shell: bash
continue-on-error: true
run: |
curl -O https://download.clojure.org/install/linux-install-${{ inputs.clojure-version }}.sh &&
sudo bash ./linux-install-${{ inputs.clojure-version }}.sh
for attempt in 1 2 3; do
curl --retry 3 --retry-delay 5 --fail -O https://download.clojure.org/install/linux-install-${{ inputs.clojure-version }}.sh \
&& sudo bash ./linux-install-${{ inputs.clojure-version }}.sh \
&& break
echo "::warning::Clojure install attempt $attempt failed, retrying in 10s..."
sleep 10
done
if ! clojure --version; then
echo "::error::Clojure CLI installation failed after 3 attempts"
exit 1
fi
- name: Get M2 cache key
uses: ./.github/actions/get-cache-keys
id: get-cache-keys
- name: Install uv (for Python package installation)
uses: astral-sh/setup-uv@v7
with:
enable-cache: false
version: "0.10.2" # keep in sync with mise.toml
github-token: ${{ github.token }}
- name: Restore M2 cache
uses: actions/cache/restore@v4
with:
@@ -36,3 +50,5 @@ runs:
~/.m2
~/.gitlibs
key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
restore-keys: |
${{ steps.get-cache-keys.outputs.m2-restore-key }}

View File

@@ -3,7 +3,7 @@ description: Cypress preparation steps
inputs:
working-directory:
description: "Optional working directory for yarn commands"
description: "Optional working directory for bun commands"
required: false
default: "."
@@ -15,11 +15,10 @@ outputs:
runs:
using: "composite"
steps:
- name: Install Chrome v111
uses: browser-actions/setup-chrome@v1
- name: Install Chrome v144
uses: browser-actions/setup-chrome@v2
with:
# https://chromium.cypress.io/linux/stable/111.0.5563.146
chrome-version: 1097615
chrome-version: 144
id: setup-chrome
- name: Get cache keys
@@ -34,9 +33,9 @@ runs:
- name: Ensure that Cypress executable is ready
run: |
yarn cypress install
yarn cypress cache path
yarn cypress cache list
yarn cypress verify
bun run cypress install
bun run cypress cache path
bun run cypress cache list
bun run cypress verify
shell: bash
working-directory: ${{ inputs.working-directory }}

View File

@@ -1,4 +1,5 @@
name: Prepare front-end environment
description: "Prepare the front-end environment for the CI build"
inputs:
node-version:
description: "The version of Node.js to use, overriding .nvmrc"
@@ -10,11 +11,10 @@ inputs:
runs:
using: "composite"
steps:
- name: Prepare Node.js
uses: actions/setup-node@v4
- name: Prepare Node + Bun environment
uses: ./.github/actions/prepare-node-bun
with:
node-version: ${{ inputs.node-version }} # this overrides, if present
node-version-file: ".nvmrc"
node-version: ${{ inputs.node-version }}
- name: Get cache keys
uses: ./.github/actions/get-cache-keys
@@ -27,13 +27,15 @@ runs:
~/.m2
~/.gitlibs
key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
restore-keys: |
${{ steps.get-cache-keys.outputs.m2-restore-key }}
- name: Get yarn cache directory
id: yarn-cache-dir
- name: Get bun cache directory
id: bun-cache
run: |
YARN_CACHE_DIR=$(yarn cache dir)
echo "Yarn cache directory: $YARN_CACHE_DIR"
echo "dir=$YARN_CACHE_DIR" >> $GITHUB_OUTPUT
BUN_CACHE_DIR=$(bun pm cache)
echo "Bun cache directory: $BUN_CACHE_DIR"
echo "dir=$BUN_CACHE_DIR" >> $GITHUB_OUTPUT
shell: bash
- name: Restore node_modules cache
@@ -41,17 +43,19 @@ runs:
id: node-modules-cache
with:
path: |
${{ steps.yarn-cache-dir.outputs.dir }}
${{ steps.bun-cache.outputs.dir }}
node_modules
key: ${{ steps.get-cache-keys.outputs.node-cache-key }}
restore-keys: |
${{ steps.get-cache-keys.outputs.node-restore-key }}
# postinstall lifecycle hook can be dangerous in CI so we only run it locally (see package.json)
# If a job wants to patch packages, it does so explicitly in the CI. This setting is opt-out.
# For example, we never want to cache node_modules with patches already applied so cache-generator.yml skips that step.
- name: Clean install
run: yarn install --frozen-lockfile --prefer-offline
run: bun install --frozen-lockfile
shell: bash
- name: Patch frontend dependencies
if: inputs.apply-patches == 'true'
run: yarn patch-package
run: bun run patch-package
shell: bash

View File

@@ -0,0 +1,20 @@
name: Prepare Node + Bun environment
description: "Set up Node.js and Bun for CI jobs"
inputs:
node-version:
description: "The version of Node.js to use, overriding .nvmrc"
required: false
runs:
using: "composite"
steps:
- name: Prepare Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
node-version-file: ".nvmrc"
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ github.token }}

View File

@@ -0,0 +1,14 @@
name: Prepare Release Scripts
description: Set up bun and build release scripts
runs:
using: composite
steps:
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ github.token }}
- name: Build release scripts
shell: bash
run: cd ${{ github.workspace }}/release && bun install --frozen-lockfile && bun run build

View File

@@ -0,0 +1,132 @@
name: Prepare Shoppy E2E environment
description: Shared setup steps for Shoppy E2E tests (regular and synthetic)
inputs:
commit:
description: "Commit SHA for artifact retrieval"
required: true
sample-app-branch-name:
description: "Branch name for the sample app"
required: true
sample-app-environment:
description: "Environment (production/development)"
required: true
staging-mb-all-features-token:
description: "Staging MB all features token"
required: true
shoppy-iam-role:
description: "Shoppy IAM role for AWS credentials"
required: true
shoppy-metabase-app-db-s3-bucket:
description: "S3 bucket for Shoppy app DB dump"
required: true
shoppy-metabase-app-db-s3-key:
description: "S3 key for Shoppy app DB dump"
required: true
shoppy-metabase-app-db-user:
description: "Shoppy Metabase app DB user"
required: true
shoppy-metabase-app-db-database:
description: "Shoppy Metabase app DB database"
required: true
metastore-dev-server-url:
description: "Metastore dev server URL"
required: true
shoppy-datadog-application-id:
description: "Shoppy Datadog application ID"
required: true
shoppy-datadog-client-token:
description: "Shoppy Datadog client token"
required: true
outputs:
chrome-path:
description: "Path to Chrome executable"
value: ${{ steps.cypress-prep.outputs.chrome-path }}
sample_app_branch_exists:
description: "Whether the sample app branch exists"
value: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists }}
runs:
using: "composite"
steps:
- uses: ./.github/actions/maximize-disk-space
# We have to use the latest version that does not have this issue https://github.com/docker/compose/pull/12752
- name: Set up Docker Compose
uses: docker/setup-compose-action@v1
with:
version: latest
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
commit: ${{ inputs.commit }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
with:
name: embedding-sdk-${{ inputs.commit }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Check if sample app branch exists
id: check-sample-app-branch
shell: bash
env:
SAMPLE_APP_BRANCH_NAME: ${{ inputs.sample-app-branch-name }}
run: |
REPO_URL="https://github.com/metabase/shoppy.git"
echo "Checking if branch '${SAMPLE_APP_BRANCH_NAME}' exists in ${REPO_URL}..."
if git ls-remote --exit-code --heads "$REPO_URL" "${SAMPLE_APP_BRANCH_NAME}"; then
echo "sample_app_branch_exists=true" >> $GITHUB_OUTPUT
else
echo "sample_app_branch_exists=false" >> $GITHUB_OUTPUT
fi
- name: Configure AWS credentials
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ inputs.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: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
shell: bash
run: |
aws s3 cp s3://${{ inputs.shoppy-metabase-app-db-s3-bucket }}/${{ inputs.shoppy-metabase-app-db-s3-key }} ./e2e/tmp/db_dumps/shoppy_metabase_app_db_dump.sql
- name: Prepare and launch Shoppy containers
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
shell: bash
env:
SAMPLE_APP_BRANCH_NAME: ${{ inputs.sample-app-branch-name }}
SAMPLE_APP_ENVIRONMENT: ${{ inputs.sample-app-environment }}
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ inputs.staging-mb-all-features-token }}
METASTORE_DEV_SERVER_URL: ${{ inputs.metastore-dev-server-url }}
METABASE_APP_DB_USER: ${{ inputs.shoppy-metabase-app-db-user }}
METABASE_APP_DB: ${{ inputs.shoppy-metabase-app-db-database }}
SHOPPY_DATADOG_APPLICATION_ID: ${{ inputs.shoppy-datadog-application-id }}
SHOPPY_DATADOG_CLIENT_TOKEN: ${{ inputs.shoppy-datadog-client-token }}
SHOPPY_DATADOG_SITE: "us5.datadoghq.com"
SHOPPY_DATADOG_ENV: "staging"
run: npx tsx ./e2e/runner/embedding-sdk/sample-apps/start-ci.ts shoppy-e2e
- name: Prune build cache
shell: bash
run: docker builder prune -af
- name: Log free disk space
shell: bash
run: df -h /

View File

@@ -2,9 +2,10 @@ name: Prepare Uberjar Artifact
description: Prepare and upload Metabase JAR as a GitHub artifact.
inputs:
name:
required: true
description: Artifact name
edition:
required: false
default: "ee"
description: Metabase edition (ee or oss)
runs:
using: "composite"
@@ -18,7 +19,7 @@ runs:
- name: Upload JARs as artifact
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
name: metabase-${{ inputs.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
path: |
./target/uberjar/metabase.jar
./COMMIT-ID

View File

@@ -0,0 +1,110 @@
name: Embedding SDK Bundle Size Check
description: |
Downloads the current branch's uberjar and builds the base ref's
embedding-sdk.js from source, compares their sizes,
and sets output if the size change exceeds the threshold.
inputs:
edition:
description: 'Metabase edition (ee or oss)'
required: true
base-ref-commit:
description: 'Commit SHA of the base ref (e.g. merge base).'
required: true
threshold-percent:
description: 'Percent threshold for bundle size change'
required: true
outputs:
status:
description: "Bundle size status: increased, decreased, or stable"
value: ${{ steps.compare.outputs.status }}
size_change_percent:
description: "size change percent (positive = increase, negative = decrease)"
value: ${{ steps.compare.outputs.size_change_percent }}
runs:
using: "composite"
steps:
- name: Prepare backend
uses: ./.github/actions/prepare-backend
- name: Prepare frontend
uses: ./.github/actions/prepare-frontend
- name: Download current uberjar
uses: actions/download-artifact@v4
with:
name: metabase-${{ inputs.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
path: temp/current-uberjar
- name: Extract embedding-sdk bundles from current uberjar
shell: bash
run: |
# Try new layout first (app/embedding-sdk/legacy/), fall back to old layout (app/embedding-sdk.js)
unzip -j temp/current-uberjar/target/uberjar/metabase.jar \
"frontend_client/app/embedding-sdk/legacy/embedding-sdk.js" \
-d temp/current-bundle 2>/dev/null || \
unzip -j temp/current-uberjar/target/uberjar/metabase.jar \
"frontend_client/app/embedding-sdk.js" \
-d temp/current-bundle
# Extract chunks directory if it exists (new layout only)
mkdir -p temp/current-chunks
unzip -j temp/current-uberjar/target/uberjar/metabase.jar \
"frontend_client/app/embedding-sdk/chunks/*" \
-d temp/current-chunks 2>/dev/null || true
- name: Checkout base ref
uses: actions/checkout@v4
with:
ref: ${{ inputs.base-ref-commit }}
path: temp/base-ref-src
- name: Build base-ref embedding-sdk.js
shell: bash
run: |
cd temp/base-ref-src
bun install
MB_EDITION=${{ inputs.edition }} bun run build-release
- name: Compare sizes and set output
id: compare
shell: bash
run: |
# --- Legacy (monolithic) bundle comparison ---
current_size=$(wc -c < temp/current-bundle/embedding-sdk.js) || { echo "::error::Failed to read current bundle"; exit 1; }
# Base ref: try new layout first, fall back to old
if [ -f "temp/base-ref-src/resources/frontend_client/app/embedding-sdk/legacy/embedding-sdk.js" ]; then
base_ref_size=$(wc -c < "temp/base-ref-src/resources/frontend_client/app/embedding-sdk/legacy/embedding-sdk.js")
else
base_ref_size=$(wc -c < "temp/base-ref-src/resources/frontend_client/app/embedding-sdk.js")
fi
[ "$current_size" -gt 0 ] && [ "$base_ref_size" -gt 0 ] || { echo "::error::Bundle file is empty"; exit 1; }
diff=$((current_size - base_ref_size))
percent=$(( diff * 100 / base_ref_size ))
echo "=== Legacy (monolithic) bundle ==="
echo "Current size: $current_size bytes"
echo "Base ref size: $base_ref_size bytes"
echo "Difference: $diff bytes ($percent%)"
threshold="${{ inputs.threshold-percent }}"
if [ "$percent" -gt "$threshold" ]; then
status="increased"
elif [ "$percent" -lt "$(( -threshold ))" ]; then
status="decreased"
else
status="stable"
fi
echo "status=$status" >> $GITHUB_OUTPUT
echo "size_change_percent=$percent" >> $GITHUB_OUTPUT
# --- Chunked bundle (informational) ---
if ls temp/current-chunks/*.js 1>/dev/null 2>&1; then
chunks_size=$(cat temp/current-chunks/*.js | wc -c)
echo ""
echo "=== Chunked bundle (bootstrap + chunks) ==="
echo "Total chunked size: $chunks_size bytes"
echo "chunks_size=$chunks_size" >> $GITHUB_OUTPUT
else
echo ""
echo "No chunked bundle found (expected on master)"
fi

View File

@@ -12,56 +12,32 @@ inputs:
logs-artifact-suffix:
required: false
description: Suffix to append to the test logs artifact name to avoid conflicts in matrix jobs
edition:
required: false
default: 'ee'
description: Edition to test (oss or ee)
outputs:
quarantine-skipped:
description: Whether the driver test was skipped due to quarantine
value: ${{ steps.check-driver.outputs.skip }}
test-outcome:
description: "The outcome of the test run (success, failure, cancelled, skipped)"
value: ${{ steps.run-test.outcome }}
runs:
using: "composite"
steps:
- name: Check if driver is ignored
id: check-driver
shell: bash
run: |
# If DRIVERS env var is not set, proceed with tests
if [ -z "$DRIVERS" ]; then
echo "No DRIVERS env var set. Proceeding with tests."
echo "skip=false" >> $GITHUB_OUTPUT
exit 0
fi
# Fetch CI config and check if driver should be skipped
curl -sSf -o ci-test-config.json https://raw.githubusercontent.com/metabase/ci-test-config/refs/heads/master/ci-test-config.json || true
# Check if the driver is in the ignored list (gracefully handle missing/invalid config)
IS_IGNORED=$(jq --arg driver "$DRIVERS" '.ignored.drivers // [] | contains([$driver])' ci-test-config.json 2>/dev/null || echo "false")
if [ "$IS_IGNORED" = "true" ]; then
echo "⚠️ Driver '$DRIVERS' is in the ignored list. Skipping tests."
echo "View the ignored list here: https://github.com/metabase/ci-test-config/blob/master/ci-test-config.json"
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "Driver '$DRIVERS' is not ignored. Proceeding with tests."
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Prepare back-end environment
if: steps.check-driver.outputs.skip != 'true'
uses: ./.github/actions/prepare-backend
- name: Prepare front-end environment
if: ${{ steps.check-driver.outputs.skip != 'true' && inputs.build-static-viz == 'true' }}
if: ${{ inputs.build-static-viz == 'true' }}
uses: ./.github/actions/prepare-frontend
- name: Build static viz frontend
if: ${{ steps.check-driver.outputs.skip != 'true' && inputs.build-static-viz == 'true' }}
run: yarn build-static-viz
if: ${{ inputs.build-static-viz == 'true' }}
run: bun run build-static-viz
shell: bash
env:
MB_EDITION: ee
- name: Test database driver
if: steps.check-driver.outputs.skip != 'true'
run: clojure -X:dev:ci:ee:ee-dev:drivers:drivers-dev:test ${{ inputs.test-args }}
run: clojure -X:dev:ci:${{ inputs.edition }}:${{ inputs.edition }}-dev:drivers:drivers-dev:test ${{ inputs.test-args }}
shell: bash
id: run-test
# Trunk Quarantine controls the final state of the run in the CI!
@@ -73,7 +49,7 @@ runs:
# As per the documentation: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#steps-context
# test.outcome gives us access to the result before `continue-on-error` overrides it and sets it to 'success'.
# We want test reports even if the test step gets cancelled (e.g. times out), hence we match anything that is not a 'success'.
if: ${{ steps.run-test.outcome != 'success' && steps.check-driver.outputs.skip != 'true' }}
if: ${{ steps.run-test.outcome != 'success' }}
with:
path: "target/junit/**/*_test.xml"
name: JUnit Test Report ${{ inputs.junit-name }}
@@ -82,10 +58,10 @@ runs:
list-tests: failed
fail-on-error: false
- name: Upload Logs on Failure
if: always() && steps.run-test.outcome != 'success' && steps.check-driver.outputs.skip != 'true'
if: always() && steps.run-test.outcome != 'success'
uses: actions/upload-artifact@v4
with:
name: ${{ format('test-logs-{0}{1}', github.job, (inputs.logs-artifact-suffix == '' || inputs.logs-artifact-suffix == null) && '' || format('-{0}', inputs.logs-artifact-suffix)) }}
name: ${{ format('test-logs-{0}{1}', github.job, inputs.logs-artifact-suffix && format('-{0}', inputs.logs-artifact-suffix) || '') }}
path: logs/test-log.json
retention-days: 1
# Failing to upload the artifact should never affect the outcome of the whole test run.

View File

@@ -21,6 +21,8 @@ inputs:
variant:
required: false
default: ""
previous-step-outcome:
required: true
runs:
using: "composite"
@@ -57,3 +59,4 @@ runs:
dry-run: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true }} # quarantine, but do not upload results
token: ${{ inputs.trunk-api-token }}
use-cache: true
previous-step-outcome: ${{ inputs.previous-step-outcome }}

View File

@@ -1,52 +1,55 @@
# Metabase Developer Assistant Instructions
## Frontend Development
For detailed coding standards and conventions, see `CLAUDE.md` and the skills in `.claude/skills/`.
### Repository Structure
## Code Review Standards
```
frontend/src/
├── metabase/ # Main application components and pages
├── metabase-lib/ # Query building and data modeling utilities
├── metabase-types/ # TypeScript type definitions
└── metabase/ui/ # Design system components
Review focus areas: Security → Performance → Testing → Documentation (in priority order)
e2e/ # Cypress end-to-end tests
frontend/test/ # Jest unit tests
```
When reviewing code, use these emoji prefixes to categorize feedback:
- 🔒 Security concerns
- ⚡ Performance opportunities
- 🧹 Cleanup needs
- 📚 Documentation gaps
- 🚨 Blocking issues
- 💭 Clarification questions
### Technology Stack
### Security Critical Issues
- **Framework**: React 18 with TypeScript
- **State**: Redux Toolkit
- **Styling**: CSS Modules (preferred) > Emotion styled-components
- **UI**: `metabase/ui` components built with Mantine v8
- **Build**: Rspack (primary), Webpack (legacy)
- **Testing**: Jest + React Testing Library, Cypress
- Check for hardcoded secrets, API keys, or credentials
- Look for SQL injection and XSS vulnerabilities
- Verify proper input validation and sanitization
- Review authentication and authorization logic
- Ensure enterprise features use the plugin system (no enterprise code in OSS)
### Coding Standards
### Performance Red Flags
#### Component Preferences
- Identify N+1 database query problems
- Spot inefficient loops and algorithmic issues
- Check for memory leaks and resource cleanup
- Review caching opportunities for expensive operations
- Prefer `metabase/ui`components over `metabase/common/components`
- Use `.tsx` for components, `.ts` for utilities
### Code Quality Essentials
#### Styling
- Functions should be focused and appropriately sized
- Use clear, descriptive naming conventions
- Ensure proper error handling throughout
- Remove dead code and unused imports
ALWAYS prefer Mantine style props,then CSS modules. DO NOT suggest styled components, they are deprecated.
### Review Style
#### TypeScript Migration
- Only flag actual issues worth mentioning
- Do not post "looks good" comments or congratulate following conventions
- Be specific and actionable in feedback
- Explain the "why" behind recommendations
- Ask clarifying questions when code intent is unclear
When heavily editing `.js`/`.jsx` files, create a separate PR to convert to TypeScript first, then implement changes.
### Review Format
#### Enterprise Features
- Condense feedback into as few comments as possible
- Prefer a single summary comment over dozens of inline comments
- Only use inline comments for critical issues that require immediate attention
- For non-critical issues, link to the specific line from the summary instead
- Delete all stale comments and summaries on each new push or CI run
Enterprise functionality MUST use the plugin system. It is very important to not expose enterprise code in the OSS version.
#### Testing Requirements
All PRs should include tests. Prefer Unit tests over E2E tests.
#### Localization
All user-facing strings MUST be localized using the ttag library. Localized strings should be complete phrases, do not concatenate a few separately localized strings. You should add context to strings where the meaning of the string might not be obvious in isolation: e.g. "Home" might have different words in some languages depending on whether you're talking about a dwelling or the landing page for a website.
Language-specific rules are in `.github/instructions/*.instructions.md`.

View File

@@ -26,11 +26,11 @@ frontend_ci: &frontend_ci
- ".github/workflows/frontend.yml"
frontend_configs: &frontend_configs
- "yarn.lock"
- "bun.lock"
- "**/tsconfig*.json"
- "package.json"
- "babel.config.json"
- ".eslintrc.js"
- "eslint.config.mjs"
- "postcss.config.js"
- "rspack.config.js"
- "rspack.main.config.js"
@@ -85,7 +85,9 @@ backend_ci: &backend_ci
backend_presto_kerberos:
- "**/presto_jdbc/**"
- "**/presto-jdbc/**" # the driver module has a hyphen. underscores are classpaths
- "**/presto_jdbc.clj"
- "**/presto_jdbc_test.clj"
- ".github/workflows/presto-kerberos-integration-test.yml"
backend_sources: &backend_sources
@@ -197,3 +199,15 @@ cljs:
- *shared_specs
- ".github/workflows/cljs.yml"
- "shadow-cljs.edn"
openapi:
- ".github/workflows/openapi.yml"
- "src/metabase/api/**"
- "src/metabase/api_routes/**"
- "src/metabase/*_rest/api.clj"
- "src/metabase/*/api.clj"
- "src/metabase/*/api/*.clj"
- "enterprise/backend/src/metabase_enterprise/**/api.clj"
- "enterprise/backend/src/metabase_enterprise/**/api/*.clj"
- "resources/openapi/**"
- "package.json"

View File

@@ -0,0 +1,9 @@
---
applyTo: "**/*.{clj,cljs,cljc}"
---
# Clojure/ClojureScript Code Review
When reviewing Clojure or ClojureScript code, apply the guidelines in these files:
- `.claude/skills/_shared/clojure-style-guide.md`
- `.claude/skills/clojure-review/SKILL.md`

View File

@@ -0,0 +1,9 @@
---
applyTo: "docs/**/*.md"
---
# Documentation Review
When reviewing documentation, apply the guidelines in these files:
- `.claude/skills/_shared/metabase-style-guide.md`
- `.claude/skills/docs-review/SKILL.md`

View File

@@ -0,0 +1,11 @@
---
applyTo: "**/*.{ts,tsx,js,jsx}"
---
# TypeScript/JavaScript Code Review
When reviewing TypeScript or JavaScript code, apply the guidelines in these files:
- `.claude/skills/typescript-review/SKILL.md`
- `docs/developers-guide/frontend.md`
- `frontend/CLAUDE.md`

View File

@@ -0,0 +1,52 @@
// This script is used in .github/workflows/cross-version.yml
// to generate a matrix for cross-version migration testing
/**
* Generate a CI matrix for cross-version migration testing (EE only).
*
* Creates pairs of [source, target] for testing HEAD against the last N
* minor versions in both upgrade and downgrade directions.
*
* @param {number} currentVersion - The current major version number (e.g., 59)
* @param {number} count - Number of previous minor versions to test against (default: 3)
* @returns {{ config: Array<{ source: string, target: string }> }}
*
* @example
* buildMatrix(59)
* // Returns:
* // {
* // config: [
* // { source: "HEAD", target: "v1.59.x" },
* // { source: "v1.59.x", target: "HEAD" },
* // { source: "HEAD", target: "v1.58.x" },
* // { source: "v1.58.x", target: "HEAD" },
* // { source: "HEAD", target: "v1.57.x" },
* // { source: "v1.57.x", target: "HEAD" },
* // ]
* // }
*/
function buildCrossVersionMatrix(currentVersion, count = 3) {
if (!Number.isInteger(currentVersion) || currentVersion < 1) {
throw new Error(
`Invalid currentVersion: ${currentVersion}. Must be a positive integer.`,
);
}
if (!Number.isInteger(count) || count < 1) {
throw new Error(`Invalid count: ${count}. Must be a positive integer.`);
}
const config = Array.from({ length: count }, (_, i) => currentVersion - i)
.filter((majorVersion) => majorVersion >= 1)
.flatMap((majorVersion) => {
const version = `v1.${majorVersion}.x`;
return [
{ source: "HEAD", target: version },
{ source: version, target: "HEAD" },
];
});
return { config };
}
module.exports = { buildCrossVersionMatrix };

View File

@@ -0,0 +1,242 @@
const { buildCrossVersionMatrix } = require("./build-cross-version-matrix");
describe("buildCrossVersionMatrix", () => {
describe("default behavior", () => {
it("should generate matrix with 3 versions by default", () => {
const result = buildCrossVersionMatrix(59);
expect(result).toEqual({
config: [
{ source: "HEAD", target: "v1.59.x" },
{ source: "v1.59.x", target: "HEAD" },
{ source: "HEAD", target: "v1.58.x" },
{ source: "v1.58.x", target: "HEAD" },
{ source: "HEAD", target: "v1.57.x" },
{ source: "v1.57.x", target: "HEAD" },
],
});
});
it("should use EE prefix (v1)", () => {
const result = buildCrossVersionMatrix(50);
expect(result.config[0].target).toBe("v1.50.x");
expect(result.config[1].source).toBe("v1.50.x");
});
it("should create pairs in both directions (upgrade and downgrade)", () => {
const result = buildCrossVersionMatrix(59);
const entries = result.config;
// Check HEAD -> version (upgrade test)
expect(entries.filter((e) => e.source === "HEAD")).toHaveLength(3);
// Check version -> HEAD (downgrade test)
expect(entries.filter((e) => e.target === "HEAD")).toHaveLength(3);
});
});
describe("custom count", () => {
it("should generate matrix with custom count", () => {
const result = buildCrossVersionMatrix(59, 5);
expect(result.config).toHaveLength(10); // 5 versions × 2 directions
expect(result.config).toEqual([
{ source: "HEAD", target: "v1.59.x" },
{ source: "v1.59.x", target: "HEAD" },
{ source: "HEAD", target: "v1.58.x" },
{ source: "v1.58.x", target: "HEAD" },
{ source: "HEAD", target: "v1.57.x" },
{ source: "v1.57.x", target: "HEAD" },
{ source: "HEAD", target: "v1.56.x" },
{ source: "v1.56.x", target: "HEAD" },
{ source: "HEAD", target: "v1.55.x" },
{ source: "v1.55.x", target: "HEAD" },
]);
});
it("should generate matrix with count=1", () => {
const result = buildCrossVersionMatrix(59, 1);
expect(result.config).toHaveLength(2);
expect(result.config).toEqual([
{ source: "HEAD", target: "v1.59.x" },
{ source: "v1.59.x", target: "HEAD" },
]);
});
it("should generate matrix with large count", () => {
const result = buildCrossVersionMatrix(59, 10);
expect(result.config).toHaveLength(20);
// Check first and last entries
expect(result.config[0]).toEqual({
source: "HEAD",
target: "v1.59.x",
});
expect(result.config[18]).toEqual({
source: "HEAD",
target: "v1.50.x",
});
expect(result.config[19]).toEqual({
source: "v1.50.x",
target: "HEAD",
});
});
});
describe("edge cases", () => {
it("should handle version 1", () => {
const result = buildCrossVersionMatrix(1);
expect(result).toEqual({
config: [
{ source: "HEAD", target: "v1.1.x" },
{ source: "v1.1.x", target: "HEAD" },
],
});
});
it("should stop when version would go below 1", () => {
const result = buildCrossVersionMatrix(2, 5);
// Can only generate v1.2.x and v1.1.x (2 versions, not 5)
expect(result.config).toHaveLength(4);
expect(result).toEqual({
config: [
{ source: "HEAD", target: "v1.2.x" },
{ source: "v1.2.x", target: "HEAD" },
{ source: "HEAD", target: "v1.1.x" },
{ source: "v1.1.x", target: "HEAD" },
],
});
});
it("should handle high version numbers", () => {
const result = buildCrossVersionMatrix(100, 2);
expect(result).toEqual({
config: [
{ source: "HEAD", target: "v1.100.x" },
{ source: "v1.100.x", target: "HEAD" },
{ source: "HEAD", target: "v1.99.x" },
{ source: "v1.99.x", target: "HEAD" },
],
});
});
});
describe("error handling", () => {
it("should throw for undefined currentVersion", () => {
expect(() => buildCrossVersionMatrix()).toThrow(
"Invalid currentVersion: undefined. Must be a positive integer.",
);
});
it("should throw for non-integer currentVersion", () => {
expect(() => buildCrossVersionMatrix(59.5)).toThrow(
"Invalid currentVersion: 59.5. Must be a positive integer.",
);
});
it("should throw for zero currentVersion", () => {
expect(() => buildCrossVersionMatrix(0)).toThrow(
"Invalid currentVersion: 0. Must be a positive integer.",
);
});
it("should throw for negative currentVersion", () => {
expect(() => buildCrossVersionMatrix(-1)).toThrow(
"Invalid currentVersion: -1. Must be a positive integer.",
);
});
it("should throw for NaN currentVersion", () => {
expect(() => buildCrossVersionMatrix(NaN)).toThrow(
"Invalid currentVersion: NaN. Must be a positive integer.",
);
});
it("should throw for non-integer count", () => {
expect(() => buildCrossVersionMatrix(59, 2.5)).toThrow(
"Invalid count: 2.5. Must be a positive integer.",
);
});
it("should throw for zero count", () => {
expect(() => buildCrossVersionMatrix(59, 0)).toThrow(
"Invalid count: 0. Must be a positive integer.",
);
});
it("should throw for negative count", () => {
expect(() => buildCrossVersionMatrix(59, -1)).toThrow(
"Invalid count: -1. Must be a positive integer.",
);
});
});
describe("matrix structure for GitHub Actions", () => {
it("should return object with config array", () => {
const result = buildCrossVersionMatrix(59);
expect(result).toHaveProperty("config");
expect(Array.isArray(result.config)).toBe(true);
});
it("should produce valid JSON for GitHub Actions", () => {
const result = buildCrossVersionMatrix(59);
const json = JSON.stringify(result);
expect(() => JSON.parse(json)).not.toThrow();
const parsed = JSON.parse(json);
expect(parsed.config).toHaveLength(6);
expect(parsed.config[0]).toEqual({
source: "HEAD",
target: "v1.59.x",
});
});
it("should have consistent entry structure", () => {
const result = buildCrossVersionMatrix(59, 5);
result.config.forEach((entry) => {
expect(entry).toHaveProperty("source");
expect(entry).toHaveProperty("target");
expect(typeof entry.source).toBe("string");
expect(typeof entry.target).toBe("string");
// Either source or target should be HEAD
expect(entry.source === "HEAD" || entry.target === "HEAD").toBeTruthy();
});
});
});
describe("version ordering", () => {
it("should generate versions in descending order", () => {
const result = buildCrossVersionMatrix(59, 5);
const versions = result.config
.filter((e) => e.source === "HEAD")
.map((e) => e.target);
expect(versions).toEqual([
"v1.59.x",
"v1.58.x",
"v1.57.x",
"v1.56.x",
"v1.55.x",
]);
});
it("should interleave upgrade and downgrade tests", () => {
const result = buildCrossVersionMatrix(59, 2);
expect(result.config[0]).toEqual({
source: "HEAD",
target: "v1.59.x",
});
expect(result.config[1]).toEqual({
source: "v1.59.x",
target: "HEAD",
});
expect(result.config[2]).toEqual({
source: "HEAD",
target: "v1.58.x",
});
expect(result.config[3]).toEqual({
source: "v1.58.x",
target: "HEAD",
});
});
});
});

View File

@@ -3,7 +3,7 @@ const { buildMatrix } = require("./build-e2e-matrix");
describe("buildMatrix", () => {
const options = {
java: "11",
defaultRunner: "ubuntu-22.04",
defaultRunner: "${{ vars.DEFAULT_RUNNER_KEY }}",
};
const testBuildMatrix = (entry, chunks) =>
buildMatrix(options, entry, chunks);

41
.github/scripts/csv-to-mb.js vendored Normal file
View File

@@ -0,0 +1,41 @@
/**
* jsonData must be in the format:
* [
* { column1: value1, column2: value2, ... },
* { column1: value3, column2: value4, ... },
* ...
* ]
*/
function jsonToCsvFormData(jsonData) {
const formData = new FormData();
const csvHeader = Object.keys(jsonData[0]).join(',') + '\n';
const csvContent = jsonData.map(row =>
Object.values(row).map(value => `"${String(value).replace(/"/g, '""')}"`).join(',')
).join('\n');
const blob = new Blob([csvHeader + csvContent], { type: 'text/csv' });
formData.append('file', blob, 'data.csv');
return formData;
}
function uploadCsvToMb({ baseUrl, tableId, jsonData, mode = 'append' }) {
const formData = jsonToCsvFormData(jsonData);
const operation = mode === 'replace' ? 'replace-csv' : 'append-csv';
return fetch(`${baseUrl}/api/table/${tableId}/${operation}`, {
method: 'POST',
headers: {
"x-api-key": process.env.API_KEY
},
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error(`Upload failed`);
}
return { success: true };
});
}
module.exports = { uploadCsvToMb };

40
.github/scripts/find-linear-issue.js vendored Normal file
View File

@@ -0,0 +1,40 @@
async function findLinearIssue({ githubIssueUrl, linearApiKey }) {
const response = await fetch("https://api.linear.app/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: linearApiKey,
},
body: JSON.stringify({
query: `
query {
attachmentsForURL(url: "${githubIssueUrl}") {
nodes {
issue { identifier }
}
}
}
`,
}),
});
const data = await response.json();
if (!response.ok) {
return { success: false, message: `Linear API error: ${response.status}` };
}
if (!data.data?.attachmentsForURL?.nodes?.length) {
return {
success: false,
message: `No Linear issue linked to ${githubIssueUrl}`,
};
}
return {
success: true,
issue: data.data.attachmentsForURL.nodes[0].issue.identifier,
};
}
module.exports = { findLinearIssue };

44
.github/team.json vendored
View File

@@ -1,24 +1,26 @@
{
"teams": [
{
"name": "Querying",
"label": ".Team/Querying",
"name": "Querying Platform",
"label": ".Team/QueryingPlatform",
"members": [
"ranquild",
"romeovs",
"bshepherdson",
"metamben",
"wzimrin",
"ericnormand",
"galdre"
"rileythomp",
"camsaul"
]
},
{
"name": "Drivers",
"label": ".Team/Drivers",
"name": "Graphy",
"label": ".Team/Graphy",
"members": [
"snoe",
"rileythomp"
"ranquild",
"romeovs",
"ericnormand",
"galdre",
"dpsutton",
"escherize",
"bgrabow"
]
},
{
@@ -43,9 +45,6 @@
"name": "DevEx",
"label": ".Team/DevEx",
"members": [
"camsaul",
"dpsutton",
"escherize",
"fraserdrops",
"nemanjaglumac"
]
@@ -62,7 +61,8 @@
"tsplude",
"lbrdnk",
"piranha",
"crisptrutski"
"crisptrutski",
"undrfined"
]
},
{
@@ -86,14 +86,12 @@
"eliotmetabase",
"npfitz",
"johnswanson",
"iethree",
"nvoxland",
"edpaget",
"deniskaber",
"alxnddr",
"bpander",
"andsalves",
"gantoreno"
"kevinkelleher12"
]
},
{
@@ -110,6 +108,16 @@
"uladzimirdev",
"egorgrushin"
]
},
{
"name": "Growth Eng",
"label": ".Team/GrowthEng",
"members": [
"iethree",
"bpander",
"gantoreno",
"losrebellos"
]
}
]
}

View File

@@ -14,20 +14,20 @@ concurrency:
jobs:
be-tests-mariadb:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
version:
- name: MariaDB 10.2
junit-name: be-tests-mariadb-10-2-ee
image: circleci/mariadb:10.2.23
- name: MariaDB 10.6
junit-name: be-tests-mariadb-10-6-ee
image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
env:
enable-ssl-tests: 'false'
- name: MariaDB Latest
junit-name: be-tests-mariadb-latest-ee
image: circleci/mariadb:latest
image: mariadb:latest
env:
enable-ssl-tests: 'false'
job:
@@ -57,8 +57,8 @@ jobs:
ports:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: circle_test
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
env:
# Only run old migrations tests on pushes to master or release branches. All other branches should skip tests
# with the tag `mb/old-migrations-test`. `__ADDITIONAL_EXCLUDED_TAG__` is not used anywhere outside of splicing
@@ -81,7 +81,7 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
#
@@ -100,11 +100,12 @@ jobs:
MB_MYSQL_SSL_TEST_USER: metabase
MB_MYSQL_SSL_TEST_PASSWORD: ${{ secrets.MYSQL_RDS_SSL_INSTANCE_PASSWORD }}
# for historic reasons (I don't want to mess around with required jobs) the job name should be something like
# "be-tests-mariadb-10-2-ee (0)"
# "be-tests-mariadb-10-6-ee (0)"
name: "${{ matrix.version.name }} ${{ matrix.job.name }}"
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -123,18 +124,19 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-mysql:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
version:
- name: MySQL 8.0
junit-name: be-tests-mysql-8-0-ee
image: cimg/mysql:8.0
- name: MySQL 8.4
junit-name: be-tests-mysql-8-4-ee
image: mysql:8.4
env:
enable-ssl-tests: 'false'
enable-aws-iam-tests: 'false'
@@ -172,7 +174,7 @@ jobs:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: circle_test
MYSQL_DATABASE: mb_test
env:
# Only run old migrations tests on pushes to master or release branches. All other branches should skip tests
# with the tag `mb/old-migrations-test`. `__ADDITIONAL_EXCLUDED_TAG__` is not used anywhere outside of splicing
@@ -195,7 +197,7 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
#
@@ -222,11 +224,12 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_AURORA_IAM_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_AURORA_IAM_SECRET_ACCESS_KEY }}
# for historic reasons (I don't want to mess around with required jobs) the job name should be something like
# "be-tests-mariadb-10-2-ee (0)"
# "be-tests-mariadb-10-6-ee (0)"
name: "${{ matrix.version.name }} ${{ matrix.job.name }}"
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -245,18 +248,19 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-postgres:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
version:
- name: Postgres 12.x
- name: Postgres 14.x
junit-name: postgres-ee
docker-image: postgres:12-alpine
docker-image: postgres:14-alpine
env:
enable-ssl-tests: 'false'
enable-aws-iam-tests: 'false'
@@ -336,6 +340,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }} (${{ matrix.job.name }})
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -354,13 +359,14 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
app-db-tests-result:
needs:
- be-tests-mariadb
- be-tests-mysql
- be-tests-postgres
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
name: app-db-tests-result
if: always() && !cancelled()

View File

@@ -11,7 +11,7 @@ on:
jobs:
deploy:
name: Publish Athena JDBC Driver
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
steps:
- name: Check out the code

View File

@@ -7,7 +7,7 @@ on:
jobs:
update_pr:
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- uses: tibdex/github-app-token@v2.1.0

View File

@@ -20,7 +20,7 @@ jobs:
github.event.label.name == 'triple-backport'
)
)
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- uses: actions/checkout@v4
with:

View File

@@ -1,109 +1,42 @@
name: Backend-Cloverage
# Module lists are generated dynamically by listing source directories.
# The setup-oss and setup-ee jobs list folders in src/metabase/ and
# enterprise/backend/src/metabase_enterprise/ respectively, convert
# underscores to dashes (for Clojure namespace convention), and output
# as JSON arrays for the matrix jobs to consume.
#
# jq flags: -R (raw string input), -s (slurp all lines into one string),
# -c (compact single-line output for GitHub Actions).
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * 1-5' # every weekday at 5am US eastern time
# re-enable once we figure out the correctness of the reports in DEV-1104
# schedule:
# - cron: '0 10 * * 1-5' # every weekday at 5am US eastern time
jobs:
setup-oss:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
outputs:
modules: ${{ steps.get-modules.outputs.modules }}
steps:
- uses: actions/checkout@v4
- id: get-modules
run: |
modules=$(ls -1d src/metabase/*/ | xargs -n1 basename | tr '_' '-' | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "modules=$modules" >> $GITHUB_OUTPUT
be-linter-cloverage:
needs: setup-oss
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
modules:
- actions
- activity-feed
- analytics
- analyze
- api
- api-keys
- api-routes
- app-db
- appearance
- audit-app
- auth-provider
- batch-processing
- bookmarks
- bug-reporting
- cache
- channel
- classloader
- cloud-migration
- cmd
- collections
- config
- connection-pool
- content-translation
- content-verification
- core
- dashboards
- database-routing
- driver
- driver-api
- eid-translation
- embedding
- events
- formatter
- geojson
- glossary
- graph
- indexed-entities
- internal-stats
- legacy-mbql
- lib
- lib-be
- logger
- login-history
- model-persistence
- models
- native-query-snippets
- notification
- parameters
- permissions
- pivot
- plugins
- premium-features
- product-feedback
- public-sharing
- pulse
- queries
- query-permissions
- query-processor
- remote-sync
- request
- revisions
- sample-data
- search
- secrets
- segments
- server
- session
- settings
- setup
- sso
- startup
- store-api
- sync
- system
- task
- task-history
- testing-api
- tiles
- timeline
- types
- upload
- user-key-value
- users
- util
- version
- view-log
- warehouse-schema
- warehouses
- xrays
modules: ${{ fromJson(needs.setup-oss.outputs.modules) }}
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
@@ -112,7 +45,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Build static viz frontend
run: yarn build-static-viz
run: bun run build-static-viz
env:
MB_EDITION: ee
- name: Collect the test coverage
@@ -130,61 +63,27 @@ jobs:
files: ./target/coverage/codecov.json
flags: back-end
setup-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
outputs:
modules: ${{ steps.get-modules.outputs.modules }}
steps:
- uses: actions/checkout@v4
- id: get-modules
run: |
modules=$(ls -1d enterprise/backend/src/metabase_enterprise/*/ | xargs -n1 basename | tr '_' '-' | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "modules=$modules" >> $GITHUB_OUTPUT
be-linter-cloverage-enterprise:
needs: setup-ee
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
modules:
- action-v2
- advanced-config
- advanced-permissions
- ai-entity-analysis
- ai-sql-fixer
- ai-sql-generation
- analytics
- api
- audit-app
- auth-provider
- billing
- bookmarks
- cache
- cloud-add-ons
- comments
- content-translation
- content-verification
- core
- dashboard-subscription-filters
- database-replication
- database-routing
- dependencies
- documents
- email
- embedding-hub
- gsheets
- harbormaster
- impersonation
- internal-stats
- llm
- metabot-v3
- permission-debug
- premium-features
- public-sharing
- remote-sync
- sandbox
- scim
- search
- semantic-search
- serialization
- snippet-collections
- sso
- stale
- transforms
- transforms-python
- upload-management
modules: ${{ fromJson(needs.setup-ee.outputs.modules) }}
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
@@ -193,7 +92,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Build static viz frontend
run: yarn build-static-viz
run: bun run build-static-viz
env:
MB_EDITION: ee
- name: Collect the test coverage

View File

@@ -14,7 +14,7 @@ concurrency:
jobs:
be-linter-clj-kondo:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
name: Clj-Kondo
steps:
@@ -26,7 +26,7 @@ jobs:
be-linter-eastwood:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 20
name: Eastwood
steps:
@@ -36,10 +36,22 @@ jobs:
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood
name: Run Eastwood linter
be-linter-eastwood-test:
if: ${{ !inputs.skip && github.ref_name == 'master' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
name: Eastwood (tests only)
steps:
- uses: actions/checkout@v4
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood/test
name: Run Eastwood linter on our backend tests
be-tests:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -104,7 +116,7 @@ jobs:
with:
java-version: "${{ matrix.java-version }}"
- name: Build static-viz frontend
run: yarn build-static-viz
run: bun run build-static-viz
env:
MB_EDITION: ${{ matrix.job.edition }}
@@ -130,6 +142,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-java-tests.outcome }}
- name: Publish Test Report (JUnit)
uses: dorny/test-reporter@v1
@@ -154,7 +167,7 @@ jobs:
# as `:dev` dependencies). See #27009 for more context.
be-check:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
strategy:
matrix:
@@ -170,7 +183,7 @@ jobs:
be-cljfmt:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
name: Cljfmt
steps:
@@ -183,12 +196,13 @@ jobs:
be-tests-result:
needs:
- be-linter-eastwood
- be-linter-eastwood-test
- be-linter-clj-kondo
- be-cljfmt
- be-check
- be-tests
if: always() && !cancelled()
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
env:
needs: ${{ toJson(needs) }}

View File

@@ -10,7 +10,7 @@ on:
jobs:
backport-reminder:
name: Decide whether to backport or not
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
steps:
- uses: jesusvasquez333/verify-pr-label-action@v1.4.0

View File

@@ -5,7 +5,7 @@ on:
jobs:
check-source-branch:
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- name: Block master branch PRs
if: github.head_ref == 'master'

View File

@@ -14,14 +14,16 @@ on:
jobs:
start-message:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Send build start message
uses: actions/github-script@v7
env:
@@ -43,7 +45,7 @@ jobs:
}).catch(console.error);
trigger-milestone-check:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
needs: start-message
steps:
@@ -64,7 +66,7 @@ jobs:
check-version:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
outputs:
ee: ${{ fromJson(steps.canonical_version.outputs.result).ee }}
@@ -79,9 +81,11 @@ jobs:
exit 1
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Version
uses: actions/github-script@v7
id: canonical_version
@@ -114,16 +118,18 @@ jobs:
return versions;
check-commit:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
steps:
- name: Check out the code to verify the release branch
uses: actions/checkout@v4
with:
fetch-depth: 0 # IMPORTANT! to get all the branches
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Branch
uses: actions/github-script@v7
id: release_branch
@@ -135,15 +141,16 @@ jobs:
const releaseBranch = getReleaseBranch(version);
return releaseBranch;
- name: Ensure that the specified commit exists in the ${{ steps.release_branch.outputs.result }} release branch
run: |
run: | # bash
RELEASE_BRANCH=${{ steps.release_branch.outputs.result }}
git checkout $RELEASE_BRANCH
git branch --contains ${{ inputs.commit }} | grep -q $RELEASE_BRANCH \
&& echo "Commit found in correct release branch" \
|| (echo "Commit not found in correct release branch" && exit 1)
git checkout -
get-build-requirements:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
outputs:
java_version: ${{ fromJson(steps.dependencies.outputs.result).java_version }}
@@ -152,9 +159,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get build dependencies
uses: actions/github-script@v7
id: dependencies
@@ -176,7 +185,7 @@ jobs:
build-uberjar-for-release:
needs: [check-version, check-commit, get-build-requirements]
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 50
strategy:
matrix:

View File

@@ -10,7 +10,7 @@ on:
jobs:
test-build-scripts:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- uses: actions/checkout@v4
- name: Prepare back-end environment

View File

@@ -39,7 +39,7 @@ concurrency:
jobs:
get-cache-keys:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- uses: actions/checkout@v4
- name: Get cache keys
@@ -52,7 +52,7 @@ jobs:
cypress-cache-key: ${{ steps.get-cache-keys.outputs.cypress-cache-key }}
generate-caches:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
needs: get-cache-keys
env:
@@ -82,7 +82,7 @@ jobs:
# Frontend preparation and caches
# `prepare-frontend` action (1) prepares Node.js and (2) fetches the node_modules cache if it exists.
# It then (3) runs `yarn install --frozen-lockfile --prefer-offline` which ensures the local cache is fully populated.
# It then (3) runs `bun install --frozen-lockfile` which ensures the local cache is fully populated.
# IMPORTANT: Caching node_modules after patches are already applied will break any PR that attempts to either:
# - upgrade a patched library
# - change a patch
@@ -92,31 +92,31 @@ jobs:
with:
apply-patches: "false"
- name: Get yarn cache directory
id: yarn-cache-dir
- name: Get bun cache directory
id: bun-cache
run: |
YARN_CACHE_DIR=$(yarn cache dir)
echo "Yarn cache directory: $YARN_CACHE_DIR"
echo "dir=$YARN_CACHE_DIR" >> $GITHUB_OUTPUT
BUN_CACHE_DIR=$(bun pm cache)
echo "Bun cache directory: $BUN_CACHE_DIR"
echo "dir=$BUN_CACHE_DIR" >> $GITHUB_OUTPUT
- name: Ensure that Cypress executable is ready
run: |
yarn cypress install
yarn cypress cache path
yarn cypress cache list
yarn cypress verify
bun run cypress install
bun run cypress cache path
bun run cypress cache list
bun run cypress verify
shell: bash
# Run Prettier to populate its cache (stored in node_modules/.cache/prettier)
# so it gets saved as part of the node_modules cache below
- name: Run Prettier to populate cache
run: yarn lint-prettier-pure
run: bun run lint-prettier-pure
- name: Update node_modules cache
uses: ./.github/actions/update-cache
with:
path: |
${{ steps.yarn-cache-dir.outputs.dir }}
${{ steps.bun-cache.outputs.dir }}
node_modules
key: ${{ env.NODE_CACHE_KEY }}
@@ -128,10 +128,10 @@ jobs:
# ESLint cache (requires both backend and frontend)
- name: Compile CLJS
run: yarn build-pure:cljs
run: bun run build-pure:cljs
- name: Run ESLint to populate cache
run: yarn lint-eslint-pure
run: bun run lint-eslint-pure
- name: Update eslint cache
uses: ./.github/actions/update-cache

View File

@@ -7,7 +7,7 @@ on:
jobs:
check-backport-script:
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v4

View File

@@ -15,7 +15,7 @@ on:
jobs:
set-milestone:
name: Automatically set milestone
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
env:
isNewReleaseBranch: ${{ github.event_name == 'workflow_dispatch' }}
@@ -26,11 +26,13 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
sparse-checkout: |
release
.github
fetch-depth: ${{ env.isNewReleaseBranch == 'false' && 3 || 0 }} # we need the full history to get all the commit messages
ref: master # we want the logic from master, even though we're triggering on a release branch
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- uses: actions/github-script@v7
if: ${{ env.isNewReleaseBranch == 'false' }}
name: Set milestone for single commit

View File

@@ -14,7 +14,7 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 3
outputs:
frontend_all: ${{ steps.changes.outputs.frontend_all }}
@@ -30,7 +30,7 @@ jobs:
fe-chromatic:
needs: files-changed
if: contains(github.event.pull_request.labels.*.name, 'chromatic') || (github.ref_name == 'master' && needs.files-changed.outputs.frontend_all == 'true')
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -41,7 +41,7 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: NODE_ENV=development yarn build-pure:cljs
run: NODE_ENV=development bun run build-pure:cljs
- name: Publish to Chromatic
uses: chromaui/action@v10.2.0
env:

View File

@@ -1,326 +0,0 @@
name: "Claude Code Bug Fix"
on:
issues:
types:
- labeled
pull_request_review:
types:
- submitted
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to fix"
required: true
type: string
override_employee_check:
description: "Override employee check for issue creator"
required: false
default: false
type: boolean
jobs:
auto-fix-bug:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
if: |
(github.event_name == 'issues' && github.event.label.name == 'Claude Bug Fix' && github.event.issue.state == 'open') ||
(github.event_name == 'workflow_dispatch') ||
(github.event_name == 'pull_request_review' && github.event.review.state == 'changes_requested' && startsWith(github.event.pull_request.head.ref, 'claude-fix/'))
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get issue data and check employee status
id: get_issue
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { getIssueData } = require('${{ github.workspace }}/.github/scripts/get-issue-data.js');
try {
const result = await getIssueData({
context,
github,
manualIssueNumber: '${{ github.event.inputs.issue_number }}'
});
const { issueNumber, issueData, employeeComments, prReviews, triggerType, isIssueAuthorEmployee } = result;
// Check employee status and fail if not authorized
if (!result.isIssueAuthorEmployee && '${{ github.event.inputs.override_employee_check }}' !== 'true') {
core.setFailed(`User ${result.issueData.user.login} is not a Metabase employee. Skipping bug fix automation.`);
}
core.setOutput('issue_number', issueNumber);
core.setOutput('issue_data', JSON.stringify(issueData));
core.setOutput('issue_comments', JSON.stringify(employeeComments));
core.setOutput('pr_reviews', JSON.stringify(prReviews));
core.setOutput('trigger_type', triggerType);
} catch (error) {
core.setFailed(error.message);
}
- name: Set up git configuration
run: |
git config --global user.name "Claude Code[bot]"
git config --global user.email "noreply@anthropic.com"
- name: Prepare issue context and bug fix prompt
id: prepare_prompt
uses: actions/github-script@v7
env:
ISSUE_DATA: ${{ steps.get_issue.outputs.issue_data }}
ISSUE_COMMENTS: ${{ steps.get_issue.outputs.issue_comments }}
PR_REVIEWS: ${{ steps.get_issue.outputs.pr_reviews }}
TRIGGER_TYPE: ${{ steps.get_issue.outputs.trigger_type }}
with:
script: |
const issueData = JSON.parse(process.env.ISSUE_DATA);
const issueComments = JSON.parse(process.env.ISSUE_COMMENTS);
const prReviews = JSON.parse(process.env.PR_REVIEWS);
const triggerType = process.env.TRIGGER_TYPE;
const issueNumber = '${{ steps.get_issue.outputs.issue_number }}';
// Convert issue title to kebab case and create branch name
const issueTitle = issueData.title || 'untitled';
const kebabTitle = issueTitle
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.replace(/-+/g, '-')
.substring(0, 50);
const branchName = `claude-fix/issue-${issueNumber}-${kebabTitle}`;
// Format data for bash environment
const formattedComments = issueComments.length > 0
? issueComments.map(comment =>
`**Comment by @${comment.user.login} on ${comment.created_at}:**\n${comment.body}`
).join('\n\n---\n\n')
: '';
const formattedReviews = prReviews.length > 0
? prReviews.map(review =>
`**Review by @${review.user.login} on ${review.submitted_at} (Changes Requested):**\n${review.body || 'No review comment provided'}`
).join('\n\n---\n\n')
: '';
core.exportVariable('BRANCH_NAME', branchName);
core.exportVariable('ISSUE_NUMBER', issueNumber);
core.exportVariable('ISSUE_TITLE', issueData.title);
core.exportVariable('ISSUE_AUTHOR', issueData.user.login);
core.exportVariable('ISSUE_CREATED', issueData.created_at);
core.exportVariable('ISSUE_BODY', issueData.body || 'No description provided');
core.exportVariable('ISSUE_COMMENTS_FORMATTED', formattedComments);
core.exportVariable('PR_REVIEWS_FORMATTED', formattedReviews);
core.exportVariable('TRIGGER_TYPE', triggerType);
- name: Generate bug fix prompt
run: |
cat << 'EOF' >> $GITHUB_ENV
BUG_FIX_PROMPT<<PROMPT_END
You are helping to fix a bug reported in GitHub issue #${{ env.ISSUE_NUMBER }}.
## Bug Report Details
**Title:** ${{ env.ISSUE_TITLE }}
**Reporter:** ${{ env.ISSUE_AUTHOR }}
**Created:** ${{ env.ISSUE_CREATED }}
**Description:**
${{ env.ISSUE_BODY }}
**Comments:**
${{ env.ISSUE_COMMENTS_FORMATTED }}
EOF
# Add review feedback section only if this is a review trigger
if [ "${{ env.TRIGGER_TYPE }}" = "pull_request_review" ]; then
cat << 'EOF' >> $GITHUB_ENV
## Previous Fix Attempt - Review Feedback (MUST ADDRESS)
Your previous automated fix attempt received the following feedback that needs to be addressed:
${{ env.PR_REVIEWS_FORMATTED }}
EOF
fi
# Add the rest of the prompt (always the same)
cat << 'EOF' >> $GITHUB_ENV
## Instructions
1. **Analyze the issue description and comments** - Understand what the issue is describing
a. Pay particular attention to reproduction steps and if there's an agreed upon fix.
2. **Search the codebase** - Use Grep and Glob tools to find relevant files
3. **Implement a fix** - Use the appropriate write skill based on the file types:
- Use clojure-write for Clojure/ClojureScript files
- Use typescript-write for TypeScript/JavaScript files
- Follow the coding standards and patterns in each skill
4. **Test the fix** - Run appropriate tests as specified in the skills
5. **Verify the fix** - Ensure tests pass and code follows conventions
## Important Guidelines
- Use the appropriate write skill for the language you're working in
- Write failing tests first, then fix them
- Work in small, testable increments
- Don't commit changes - leave that for the workflow
- IMPORTANT: Focus only on fixing the reported bug, don't make unrelated changes
## Scratchpad Directory
A `.claude-scratchpad/` directory has been created for your temporary files:
- Use this directory for ALL temporary verification files. However, prefer using production test files rather than adhoc ones.
- Only modify actual production code in the main repository directories
- The scratchpad will be cleaned up automatically - nothing from it will be committed
Start by understanding the bug and then systematically work toward a solution.
PROMPT_END
EOF
- name: Determine branch strategy
run: |
BRANCH_NAME="${{ env.BRANCH_NAME }}"
if git branch -r --list "origin/${BRANCH_NAME}" | grep -q .; then
echo "Branch already exists: $BRANCH_NAME"
echo "Will push to existing branch and skip PR creation"
echo "BRANCH_EXISTS=true" >> $GITHUB_ENV
else
echo "Creating new branch: $BRANCH_NAME"
echo "Will create new PR"
echo "BRANCH_EXISTS=false" >> $GITHUB_ENV
fi
# Export the branch name
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
- name: Create scratchpad directory for Claude
run: |
# Create a scratchpad directory for Claude to use for temporary files
mkdir -p .claude-scratchpad
echo "Scratchpad directory created for Claude's temporary verification files"
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
- name: Generate Bug Fix with Claude Code
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
prompt: ${{ env.BUG_FIX_PROMPT }}
claude_args: |
--allowedTools "Bash(yarn test-unit*),Bash(yarn lint-eslint-pure),Bash(./bin/mage*),Bash(clojure*),Bash(find*),Bash(ls*),Bash(grep*),Write,Read,Glob,Grep,Edit,MultiEdit"
--disallowedTools "Bash(git commit*),Bash(git push*),Bash(gh*)"
- name: Clean up scratchpad directory
run: |
# Remove the scratchpad directory so its contents don't get committed
rm -rf .claude-scratchpad/
# Remove output file generated by Claude Code action
rm -f output.txt
echo "Scratchpad directory and action output files cleaned up"
- name: Check for changes and analysis
id: check_changes
run: |
# Now check for actual code changes (excluding analysis file)
if [ -n "$(git status --porcelain)" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "Changes detected:"
git status --short
else
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes made by Claude."
fi
- name: Get issue team labels and prepare reviewers
if: steps.check_changes.outputs.has_changes == 'true'
id: prepare_reviewers
uses: actions/github-script@v7
env:
ISSUE_DATA: ${{ steps.get_issue.outputs.issue_data }}
with:
script: |
const issueData = JSON.parse(process.env.ISSUE_DATA);
const issueLabels = issueData.labels.map(label => label.name);
const teamLabels = issueLabels.filter(label => label.startsWith('.Team/'));
const issueCreator = issueData.user.login;
core.setOutput('team_labels', teamLabels.join(','));
core.setOutput('reviewers', issueCreator);
- name: Create Pull Request
if: steps.check_changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ env.BRANCH_NAME }}
base: master
commit-message: |
Fix: ${{ env.ISSUE_TITLE }}
Fixes #${{ env.ISSUE_NUMBER }}
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
committer: "Claude Code[bot] <noreply@anthropic.com>"
author: "Claude Code[bot] <noreply@anthropic.com>"
title: "Fix: ${{ env.ISSUE_TITLE }}"
body: |
This PR automatically fixes the bug reported in #${{ env.ISSUE_NUMBER }}.
## Bug Report
**Original Issue:** #${{ env.ISSUE_NUMBER }}
**Reporter:** @${{ env.ISSUE_AUTHOR }}
**Issue Title:** ${{ env.ISSUE_TITLE }}
## Automated Fix
🤖 This fix was generated automatically by Claude Code based on the issue description.
**Please review carefully:**
- [ ] The fix addresses the reported issue
- [ ] Tests pass and code follows conventions
- [ ] No unrelated changes were introduced
- [ ] The solution is appropriate and maintainable
## Next Steps
- Review the changes and test thoroughly
- If the fix looks good, approve and merge
- If issues are found, either fix them or close this PR
---
Closes #${{ env.ISSUE_NUMBER }}
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
labels: |
${{ steps.prepare_reviewers.outputs.team_labels }}
automated-fix
ci skip
reviewers: ${{ steps.prepare_reviewers.outputs.reviewers }}
- name: Log existing branch update
if: steps.check_changes.outputs.has_changes == 'true' && env.BRANCH_EXISTS == 'true'
uses: actions/github-script@v7
with:
script: |
console.log('🔄 Updated existing branch: ${{ env.BRANCH_NAME }}');
console.log('The changes have been pushed to the existing PR for this issue.');
- name: Log analysis for no changes
if: steps.check_changes.outputs.has_changes == 'false'
uses: actions/github-script@v7
with:
script: |
console.log('🤖 No code changes were made by Claude.');

View File

@@ -1,98 +0,0 @@
name: "Claude Code Review"
on:
pull_request:
types:
- closed
- synchronize
- labeled
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-claude-code-review
cancel-in-progress: true
jobs:
review:
if: |
(
github.event.action == 'closed' &&
github.event.pull_request.merged == true
) ||
contains(github.event.pull_request.labels.*.name, 'Claude Code Review')
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
# Make sure the value of GITHUB_TOKEN will not be persisted in repo's config
persist-credentials: false
# Apparently comments on specific lines and top-level comments about the PR as a whole are TWO TOTALLY DIFFERENT
# TYPES OF THINGS. So we have to fetch and delete separately.
- name: Delete old Claude PR review comments
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
shell: bash
run: |
# Get old comment IDs from the bot
old_line_comment_ids=$(gh api "/repos/$REPO/pulls/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
echo "Deleting line comments: $old_line_comment_ids"
# Delete each comment
for id in $old_line_comment_ids; do
gh api -X DELETE "/repos/$REPO/pulls/comments/$id"
echo "Deleted line comment $id"
done
# Get old top-level comment IDs (technically "issue" comments on the PR?)
old_top_level_comment_ids=$(gh api "/repos/$REPO/issues/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
echo "Deleting top-level comments: $old_top_level_comment_ids"
# Delete each comment
for id in $old_top_level_comment_ids; do
gh api -X DELETE "/repos/$REPO/issues/comments/$id"
echo "Deleted top-level comment $id"
done
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
permission-contents: read # Required for reading repository files and PR diffs
permission-pull-requests: write # Required for creating inline comments and PR comments
- name: Fetch Community Clojure Style Guide
run: >-
curl https://raw.githubusercontent.com/bbatsov/clojure-style-guide/refs/heads/master/README.adoc -o CLOJURE_STYLE_GUIDE.adoc
- uses: anthropics/claude-code-action@v1
timeout-minutes: 10
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Review this pull request for compliance with project coding standards and conventions.
**Use the appropriate review skill based on the file types changed:**
- Use clojure-review for Clojure/ClojureScript files
- Use typescript-review for TypeScript/JavaScript files
- Follow the review guidelines and checklists in each skill
DO NOT post any comments confirming that something is correct - only post comments for style violations or concerns.
Note: The PR branch is already checked out in the current working directory.
Use `gh pr comment` for top-level feedback.
Use `mcp__github_inline_comment__create_inline_comment` to highlight specific code issues.
Only post GitHub comments - don't submit review text as messages.
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),ReadFile(CLOJURE_STYLE_GUIDE.adoc)"

View File

@@ -1,101 +0,0 @@
name: "Claude Docs Review"
on:
pull_request:
types:
- opened
- synchronize
- reopened
paths:
- 'docs/**/*.md'
- 'docs/**/*.mdx'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: number
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-claude-docs-review
cancel-in-progress: true
jobs:
review:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
# Make sure the value of GITHUB_TOKEN will not be persisted in repo's config
persist-credentials: false
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
permission-contents: read # Required for reading repository files and PR diffs
permission-pull-requests: write # Required for creating inline comments and PR comments
- name: Delete old Claude docs review comments
env:
GH_TOKEN: ${{ steps.claude-app-token.outputs.token }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
shell: bash
run: |
# Delete pending reviews first (these can be deleted entirely)
pending_review_ids=$(gh api "/repos/$REPO/pulls/$PR_NUMBER/reviews" --jq '.[] | select(.user.login=="metabase-bot[bot]" and .state=="PENDING") | .id')
if [ -n "$pending_review_ids" ]; then
echo "Deleting pending reviews: $pending_review_ids"
for id in $pending_review_ids; do
gh api -X DELETE "/repos/$REPO/pulls/$PR_NUMBER/reviews/$id"
echo "Deleted pending review $id"
done
fi
# Delete individual inline comments from submitted reviews (can't delete the review itself)
old_line_comment_ids=$(gh api "/repos/$REPO/pulls/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
if [ -n "$old_line_comment_ids" ]; then
echo "Deleting line comments: $old_line_comment_ids"
for id in $old_line_comment_ids; do
gh api -X DELETE "/repos/$REPO/pulls/comments/$id"
echo "Deleted line comment $id"
done
fi
# Delete top-level review comments
old_top_level_comment_ids=$(gh api "/repos/$REPO/issues/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
if [ -n "$old_top_level_comment_ids" ]; then
echo "Deleting top-level comments: $old_top_level_comment_ids"
for id in $old_top_level_comment_ids; do
gh api -X DELETE "/repos/$REPO/issues/comments/$id"
echo "Deleted top-level comment $id"
done
fi
- uses: anthropics/claude-code-action@v1
timeout-minutes: 10
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
show_full_output: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
Review the documentation changes in this pull request.
Use the docs-review skill to review all changed documentation files for compliance with the Metabase writing style guide.
DO NOT post any comments confirming that something is correct - only post comments for style violations or concerns.
claude_args: |
--allowedTools "Skill,mcp__github__get_pull_request,mcp__github__get_pull_request_files,mcp__github__create_pending_pull_request_review,mcp__github__get_pull_request_diff,mcp__github__add_comment_to_pending_review,mcp__github__add_pull_request_review_comment_to_pending_review,mcp__github__delete_pending_pull_request_review,mcp__github__submit_pending_pull_request_review"

View File

@@ -1,33 +0,0 @@
name: Cleanup caches by a branch
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
REPO=${{ github.repository }}
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -14,7 +14,7 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 3
outputs:
cljs: ${{ steps.changes.outputs.cljs }}
@@ -30,7 +30,7 @@ jobs:
shared-tests-cljs:
needs: files-changed
if: needs.files-changed.outputs.cljs == 'true'
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
@@ -39,4 +39,4 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Run Cljs tests
run: yarn run test-cljs
run: bun run test-cljs

View File

@@ -10,7 +10,7 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 3
outputs:
codeql: ${{ steps.changes.outputs.codeql }}
@@ -25,7 +25,7 @@ jobs:
analyze:
needs: files-changed
if: needs.files-changed.outputs.codeql == 'true'
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

View File

@@ -1,19 +1,118 @@
name: Codespell
on:
push:
branches:
- 'master'
- 'release-**'
pull_request:
schedule:
# Run nightly at 4:00 AM UTC
- cron: "0 4 * * *"
workflow_dispatch:
jobs:
codespell:
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v3
- uses: codespell-project/actions-codespell@v1
- uses: actions/checkout@v4
- name: Install codespell
run: pip install codespell
- name: Set up git configuration
run: |
git config --global user.name "Claude Code[bot]"
git config --global user.email "noreply@anthropic.com"
- name: Get current date
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- name: Run codespell check
id: codespell_check
continue-on-error: true
run: |
set -o pipefail
./bin/mage codespell 2>&1 | tee codespell_output.txt
- name: Generate GitHub App Token for Claude
if: steps.codespell_check.outcome == 'failure'
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
# keep this list in sync with the list in `mage/src/mage/codespell.yml`
path: >-
docs
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
- name: Build Claude prompt
if: steps.codespell_check.outcome == 'failure'
run: |
cat > /tmp/claude_prompt.txt << 'PROMPT_HEADER'
You are tasked with fixing spelling errors detected by codespell in this repository.
## Codespell Output
The following spelling errors were detected:
```
PROMPT_HEADER
cat codespell_output.txt >> /tmp/claude_prompt.txt
cat >> /tmp/claude_prompt.txt << 'PROMPT_FOOTER'
```
## Instructions
1. **Review the codespell output and identify reported spelling errors** - The usual format codespell uses is `typo ==> correction`
2. **Fix every spelling error** - Use the Edit tool to fix each misspelling with the suggested correction
- If codespell suggests multiple corrections, choose the most appropriate one based on context
Human reviewers will verify the changes before merging, so fix all errors reported by codespell.
PROMPT_FOOTER
- name: Fix spelling errors with Claude Code
if: steps.codespell_check.outcome == 'failure'
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
prompt_file: /tmp/claude_prompt.txt
claude_args: |
--allowedTools "Write,Read,Glob,Grep,Edit,MultiEdit,Bash(cat*),Bash(ls*)"
--disallowedTools "Bash(git commit*),Bash(git push*),Bash(gh*)"
- name: Clean up temporary files
if: steps.codespell_check.outcome == 'failure'
run: rm -f codespell_output.txt
- name: Create Pull Request
if: steps.codespell_check.outcome == 'failure'
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: claude-fix/codespell-${{ steps.date.outputs.date }}
base: master
delete-branch: true
commit-message: |
Fix spelling errors detected by codespell (${{ steps.date.outputs.date }})
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
committer: "Claude Code[bot] <noreply@anthropic.com>"
author: "Claude Code[bot] <noreply@anthropic.com>"
title: "Fix spelling errors detected by codespell (${{ steps.date.outputs.date }})"
body: |
This PR automatically fixes spelling errors detected by the scheduled codespell check.
## Automated Fix
🤖 This fix was generated automatically by Claude Code based on codespell output.
**Please review carefully:**
- [ ] The spelling fixes are correct
- [ ] No code functionality was changed
- [ ] Technical terms were preserved correctly
---
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
labels: |
automated-fix
backport

View File

@@ -4,8 +4,10 @@ run-name: Containerize ${{ inputs.tag }} Uberjar
on:
workflow_call:
inputs:
artifact-name:
edition:
description: Metabase edition (ee or oss)
type: string
required: true
repo:
description: owner and repo like "metabase/metabase"
type: string
@@ -15,14 +17,18 @@ on:
type: string
release:
type: string
default: 'true'
default: 'false'
build-args:
type: string
workflow_dispatch:
inputs:
artifact-name:
description: usually something like "metabase-release-{{ edition }}-{{ hash }}-uberjar"
type: string
edition:
description: Metabase edition (ee or oss)
type: choice
options:
- ee
- oss
required: true
repo:
description: docker owner and repo like "metabase/metabase"
type: string
@@ -32,10 +38,17 @@ on:
commit:
description: the full commit hash
type: string
release:
description: Whether this is a release artifact (uses metabase-release- prefix)
type: choice
options:
- "false"
- "true"
default: "false"
jobs:
containerize:
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 15
outputs:
platforms: ${{ steps.platforms.outputs.result }}
@@ -45,12 +58,14 @@ jobs:
fetch-depth: 0
# we want the dockerfile from the commit we're building
- run: git checkout ${{ inputs.commit }} -- bin/docker
- name: Retrieve test build uberjar artifact
- name: Retrieve uberjar artifact
uses: ./.github/actions/fetch-artifact
with:
name: ${{ inputs.artifact-name }}
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
commit: ${{ inputs.commit }}
edition: ${{ inputs.edition }}
release: ${{ inputs.release }}
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get platforms
id: platforms
uses: actions/github-script@v7
@@ -102,7 +117,7 @@ jobs:
bin/docker/.
verify-docker-pull:
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
needs: containerize
timeout-minutes: 15
steps:

View File

@@ -6,7 +6,7 @@ on:
jobs:
get-container-info:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
name: Get container info
outputs:
@@ -55,28 +55,28 @@ jobs:
uses: ./.github/workflows/containerize-jar.yml
secrets: inherit
with:
artifact-name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.inputs.commit || github.sha }}
edition: ${{ matrix.edition }}
commit: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
repo: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).repo }}
tag: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).tag }}
release: "false"
build-args: |
GIT_COMMIT_SHA=${{ github.event.inputs.commit || github.sha }}
GIT_COMMIT_SHA=${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
run-trivy:
needs: [get-container-info, containerize]
strategy:
matrix:
edition: ${{ fromJson(needs.get-container-info.outputs.editions) }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
name: Run Trivy vulnerability scanner
steps:
- name: Check out the code
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commit || github.sha }}
ref: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.29.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1
env:
TRIVY_OFFLINE_SCAN: true
repo: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).repo }}
@@ -85,7 +85,6 @@ jobs:
image-ref: docker.io/${{ env.repo }}:${{ env.tag }}
format: sarif
output: trivy-results.sarif
version: "v0.57.1"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
@@ -94,7 +93,7 @@ jobs:
post-comment:
needs: [get-container-info, containerize]
if: github.event_name == 'pull_request'
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
name: Post PR comment
steps:
- name: Check out the code

View File

@@ -8,7 +8,7 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 3
outputs:
frontend_embedding_sources: ${{ steps.changes.outputs.frontend_embedding_sources }}
@@ -22,7 +22,7 @@ jobs:
filters: .github/file-paths.yaml
pr-title-reminder:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
permissions:
pull-requests: write

View File

@@ -7,7 +7,7 @@ on:
jobs:
fe-test-coverage:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
@@ -17,7 +17,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Run frontend unit tests
run: |
yarn run test-unit \
bun run test-unit \
--silent \
--coverage \
--testTimeout=60000

View File

@@ -25,7 +25,7 @@ concurrency:
jobs:
migrations-h2-ee:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
@@ -38,24 +38,24 @@ jobs:
base-ref: ${{ env.BASE_REF }}
head-ref: ${{ env.HEAD_REF }}
migrations-postgres-12-ee:
runs-on: ubuntu-22.04
migrations-postgres-14-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
MB_DB_HOST: localhost
MB_DB_DBNAME: circle_test
MB_DB_USER: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: mb_test
services:
postgres:
image: postgres:12-alpine
image: postgres:14-alpine
ports:
- "5432:5432"
env:
POSTGRES_USER: circle_test
POSTGRES_DB: circle_test
POSTGRES_USER: mb_test
POSTGRES_DB: mb_test
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4
@@ -65,23 +65,23 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-postgres-latest-ee:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
MB_DB_HOST: localhost
MB_DB_DBNAME: circle_test
MB_DB_USER: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: mb_test
services:
postgres:
image: circleci/postgres:latest
image: postgres:latest
ports:
- "5432:5432"
env:
POSTGRES_USER: circle_test
POSTGRES_DB: circle_test
POSTGRES_USER: mb_test
POSTGRES_DB: mb_test
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4
@@ -90,21 +90,24 @@ jobs:
base-ref: ${{ env.BASE_REF }}
head-ref: ${{ env.HEAD_REF }}
migrations-mysql-8-0-ee:
runs-on: ubuntu-22.04
migrations-mysql-8-4-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: root
services:
mysql:
image: cimg/mysql:8.0
image: mysql:8.4
ports:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cross-branch-migration-test
@@ -113,14 +116,14 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-mysql-latest-ee:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
services:
@@ -128,7 +131,7 @@ jobs:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: circle_test
MYSQL_DATABASE: mb_test
ports:
- "3306:3306"
steps:
@@ -138,21 +141,24 @@ jobs:
base-ref: ${{ env.BASE_REF }}
head-ref: ${{ env.HEAD_REF }}
migrations-mariadb-10-2-ee:
runs-on: ubuntu-22.04
migrations-mariadb-10-6-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: root
services:
mariadb:
image: circleci/mariadb:10.2.23
image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cross-branch-migration-test
@@ -161,20 +167,23 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-mariadb-latest-ee:
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_DBNAME: mb_test
MB_DB_USER: root
services:
mariadb:
image: circleci/mariadb:latest
image: mariadb:latest
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cross-branch-migration-test

221
.github/workflows/cross-version.yml vendored Normal file
View File

@@ -0,0 +1,221 @@
name: Cross-Version Migration Tests
on:
workflow_dispatch:
inputs:
source_version:
description: "Source version (e.g., v1.58.6 or HEAD)"
required: true
type: string
target_version:
description: "Target version (e.g., v1.58.7 or HEAD)"
required: true
type: string
pull_request:
paths:
- "cross-version/**"
- ".github/workflows/cross-version.yml"
- ".github/scripts/build-cross-version-matrix.js"
schedule:
# Run nightly at 3 AM UTC
- cron: "0 3 * * *"
jobs:
# Generate matrix for scheduled/PR runs
generate-matrix:
if: github.event_name != 'workflow_dispatch'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: .github
- name: Generate version matrix
id: set-matrix
uses: actions/github-script@v7
with:
script: |
const { buildCrossVersionMatrix } = require('${{ github.workspace }}/.github/scripts/build-cross-version-matrix');
const { config } = buildCrossVersionMatrix(${{ vars.CURRENT_VERSION }});
const matrix = JSON.stringify({ include: config });
core.setOutput("matrix", matrix);
console.log("matrix:", matrix);
# Matrix-based tests for scheduled/PR runs
test-matrix:
if: github.event_name != 'workflow_dispatch'
needs: generate-matrix
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
strategy:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare Cypress environment
uses: ./.github/actions/prepare-cypress
- name: Run cross-version test
env:
CURRENT_VERSION: ${{ vars.CURRENT_VERSION }}
RESULT_FILE: ${{ runner.temp }}/cross-version-result-${{ matrix.source }}-${{ matrix.target }}.json
run: |
cd cross-version
./test.sh --source "${{ matrix.source }}" --target "${{ matrix.target }}"
- name: Upload failure result
uses: actions/upload-artifact@v4
if: failure()
with:
name: failure-result-${{ matrix.source }}-${{ matrix.target }}
path: ${{ runner.temp }}/cross-version-result-${{ matrix.source }}-${{ matrix.target }}.json
if-no-files-found: ignore
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-${{ matrix.source }}-${{ matrix.target }}
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: Show logs on failure
if: failure()
run: |
cd cross-version
docker compose logs metabase || true
docker compose logs postgres || true
# Notify Slack on nightly failures
notify-on-failure:
if: always() && github.event_name == 'schedule' && needs.test-matrix.result == 'failure'
needs: [test-matrix]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Download failure results
uses: actions/download-artifact@v4
continue-on-error: true
with:
pattern: failure-result-*
path: failure-results
merge-multiple: true
- name: Notify Slack
continue-on-error: true
uses: actions/github-script@v7
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
with:
script: |
const fs = require('fs');
const path = require('path');
const { buildFailureResults, sendCrossVersionSlackNotification } = require('${{ github.workspace }}/release/dist/index.cjs');
// Get all failed jobs from the GitHub API
const { owner, repo } = context.repo;
const jobInfo = await github.rest.actions.listJobsForWorkflowRun({
owner,
repo,
run_id: context.runId,
per_page: 100,
});
const failedJobs = jobInfo.data.jobs
.filter(job => job.status === 'completed' && job.conclusion === 'failure' && job.name.startsWith('test-matrix'))
.map(job => ({ name: job.name, url: job.html_url }));
if (failedJobs.length === 0) {
console.log('No failed test-matrix jobs found');
return;
}
// Load artifact data for enrichment (phase)
const resultsDir = 'failure-results';
const artifactData = new Map();
if (fs.existsSync(resultsDir)) {
for (const file of fs.readdirSync(resultsDir)) {
if (!file.endsWith('.json')) continue;
try {
const result = JSON.parse(fs.readFileSync(path.join(resultsDir, file), 'utf8'));
artifactData.set(`${result.source}-${result.target}`, result);
} catch (e) {
console.log(`Skipping malformed result: ${file}`);
}
}
}
const failures = buildFailureResults(failedJobs, artifactData);
const runUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${context.runId}`;
const slackBotToken = process.env.SLACK_BOT_TOKEN;
if (!slackBotToken) {
console.log('SLACK_BOT_TOKEN is not set; skipping Slack notification.');
return;
}
await sendCrossVersionSlackNotification(failures, runUrl, slackBotToken);
console.log('Slack notification sent');
# Manual test for workflow_dispatch
test-manual:
if: github.event_name == 'workflow_dispatch'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare Cypress environment
uses: ./.github/actions/prepare-cypress
- name: Run cross-version test
env:
CURRENT_VERSION: ${{ vars.CURRENT_VERSION }}
run: |
cd cross-version
./test.sh --source "${{ inputs.source_version }}" --target "${{ inputs.target_version }}"
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-${{ inputs.source_version }}-${{ inputs.target_version }}
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: Show logs on failure
if: failure()
run: |
cd cross-version
docker compose logs metabase || true
docker compose logs postgres || true

View File

@@ -0,0 +1,79 @@
name: Disabled Drivers Slack Notification
on:
workflow_dispatch:
schedule:
- cron: "0 9 * * 1" # every Monday at 9:00 UTC
jobs:
notify-disabled-drivers:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
steps:
- uses: actions/setup-node@v4
with:
node-version: lts/Jod
- name: Install Slack SDK
run: npm install @slack/web-api
- name: Check disabled drivers and notify Slack
uses: actions/github-script@v7
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
with:
script: |
const { WebClient } = require('@slack/web-api');
// Fetch the config
const response = await fetch('https://raw.githubusercontent.com/metabase/ci-test-config/refs/heads/master/ci-test-config.json');
const config = await response.json();
const drivers = config.ignored?.drivers || [];
const lastUpdated = config.metadata?.last_updated || 'unknown';
const reason = config.metadata?.reason || 'No reason provided';
if (drivers.length === 0) {
console.log('No drivers are currently disabled. Skipping Slack notification.');
return;
}
if (!process.env.SLACK_BOT_TOKEN) {
throw new Error('SLACK_BOT_TOKEN is required');
}
const slack = new WebClient(process.env.SLACK_BOT_TOKEN);
await slack.chat.postMessage({
channel: 'engineering-ci',
text: 'CI Disabled Drivers Report',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `:no_entry: *CI Disabled Drivers*\n${drivers.map(d => `\`${d}\``).join(' ')}`
},
accessory: {
type: 'button',
text: {
type: 'plain_text',
text: 'View Config',
emoji: true
},
url: 'https://github.com/metabase/ci-test-config/blob/master/ci-test-config.json'
}
},
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: `${reason} · :clock1: *${lastUpdated}*`
}
]
}
]
});
console.log('Slack notification sent successfully');

View File

@@ -21,7 +21,7 @@ permissions:
jobs:
update-docs:
name: Update documentation for ${{ inputs.target_branch }}
runs-on: ubuntu-22.04
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
steps:
- name: Checkout code

View File

@@ -7,7 +7,7 @@ on:
jobs:
link-checker:
name: Check documentation links
runs-on: ubuntu-latest
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
permissions:
contents: read

View File

@@ -2,7 +2,7 @@ name: Auto-update documentation (master)
on:
schedule:
- cron: "0 1 * * 1-5" # Every Monday through Friday at 1 AM UTC
- cron: "0 21 * * 1-5" # Every Monday through Friday at 9 PM UTC
workflow_dispatch:
jobs:

Some files were not shown because too many files have changed in this diff Show More