feat(auto_metabase): push-all + describe/sql + auto-inject de dashcards
- push_all(): pushea todos los YAMLs de un proyecto (cards primero,
dashboards despues), solo CREATE/UPDATE, resiliente a fallos por item
- explore.py: comandos describe (schema de DB) y sql (query ad-hoc con
limite, cap 5MB, bloqueo de escrituras destructivas)
- payload.py: auto-inyecta id:-N, visualization_settings:{} y
parameter_mappings:[] en dashcards nuevas para evitar 500 en push
- test_local: 11 cards + 3 dashboards sobre Sample Database de Metabase
- registry.db regenerado con auto_metabase_py_analytics indexada
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 48
|
||||
slug: clientes_nuevos_por_mes
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.096661Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Altas mensuales en PEOPLE (CREATED_AT)
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: Clientes nuevos por mes
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT FORMATDATETIME(CREATED_AT, 'yyyy-MM') AS mes,\n COUNT(*) AS nuevos\n FROM PEOPLE\n GROUP BY mes\n\
|
||||
\ ORDER BY mes"
|
||||
parameter_mappings: []
|
||||
display: line
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,31 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 49
|
||||
slug: clientes_por_edad
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.154517Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Distribucion calculada desde BIRTH_DATE a fecha actual
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: Clientes por rango de edad
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT\n CASE\n WHEN DATEDIFF('year', BIRTH_DATE, CURRENT_DATE) < 25 THEN '1) <25'\n WHEN DATEDIFF('year',\
|
||||
\ BIRTH_DATE, CURRENT_DATE) < 35 THEN '2) 25-34'\n WHEN DATEDIFF('year', BIRTH_DATE, CURRENT_DATE) < 45 THEN '3)\
|
||||
\ 35-44'\n WHEN DATEDIFF('year', BIRTH_DATE, CURRENT_DATE) < 55 THEN '4) 45-54'\n WHEN DATEDIFF('year', BIRTH_DATE,\
|
||||
\ CURRENT_DATE) < 65 THEN '5) 55-64'\n ELSE '6) 65+'\n END AS rango_edad,\n COUNT(*) AS clientes\nFROM PEOPLE\n\
|
||||
WHERE BIRTH_DATE IS NOT NULL\nGROUP BY rango_edad\nORDER BY rango_edad"
|
||||
parameter_mappings: []
|
||||
display: bar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 46
|
||||
slug: clientes_por_estado
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.215737Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Top 10 estados (US) por numero de clientes
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: clientes_por_estado
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT STATE, COUNT(*) AS clientes\n FROM PEOPLE\n GROUP BY STATE\n ORDER BY clientes DESC\n LIMIT 10"
|
||||
parameter_mappings: []
|
||||
display: bar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,28 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 50
|
||||
slug: clientes_por_source
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.276556Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Distribucion por SOURCE (Google, Twitter, Facebook, Organic, Affiliate)
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: Clientes por canal
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT COALESCE(SOURCE, 'unknown') AS canal,\n COUNT(*) AS clientes\n FROM PEOPLE\n GROUP BY canal\n\
|
||||
\ ORDER BY clientes DESC"
|
||||
parameter_mappings: []
|
||||
display: pie
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 51
|
||||
slug: clientes_recientes
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.325878Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Tabla de las 20 altas mas recientes en PEOPLE
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: Ultimos 20 clientes registrados
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT NAME, EMAIL, CITY, STATE, SOURCE, CREATED_AT\n FROM PEOPLE\n ORDER BY CREATED_AT DESC\n LIMIT 20"
|
||||
parameter_mappings: []
|
||||
display: table
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,28 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 52
|
||||
slug: clientes_top_ciudades
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.37711Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Ciudades con mas clientes
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: Top 15 ciudades
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT CITY, STATE, COUNT(*) AS clientes\n FROM PEOPLE\n GROUP BY CITY, STATE\n ORDER BY clientes DESC\n LIMIT\
|
||||
\ 15"
|
||||
parameter_mappings: []
|
||||
display: bar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 42
|
||||
slug: clientes_total
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.441467Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Numero total de clientes en PEOPLE
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: clientes_total
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: SELECT COUNT(*) AS total FROM PEOPLE
|
||||
parameter_mappings: []
|
||||
display: scalar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,28 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 45
|
||||
slug: compras_por_mes
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.516411Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Numero de compras agrupadas por mes
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: compras_por_mes
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT FORMATDATETIME(CREATED_AT, 'yyyy-MM') AS mes,\n COUNT(*) AS compras\n FROM ORDERS\n GROUP BY\
|
||||
\ mes\n ORDER BY mes"
|
||||
parameter_mappings: []
|
||||
display: line
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 43
|
||||
slug: compras_total
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.586558Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Numero total de compras en ORDERS
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: compras_total
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: SELECT COUNT(*) AS total FROM ORDERS
|
||||
parameter_mappings: []
|
||||
display: scalar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 44
|
||||
slug: ingresos_totales
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.663393Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Suma de TOTAL de todas las compras
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: ingresos_totales
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: SELECT ROUND(SUM(TOTAL), 2) AS ingresos FROM ORDERS
|
||||
parameter_mappings: []
|
||||
display: scalar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 40
|
||||
slug: test_count_users
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.727051Z'
|
||||
_refs:
|
||||
database: metabase_internal_pg
|
||||
collection: null
|
||||
payload:
|
||||
description: otro cambio externo
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: test_count_users
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: metabase_internal_pg
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: SELECT COUNT(*) AS users FROM core_user
|
||||
parameter_mappings: []
|
||||
display: scalar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,26 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 41
|
||||
slug: test_users_by_locale
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.796377Z'
|
||||
_refs:
|
||||
database: metabase_internal_pg
|
||||
collection: null
|
||||
payload:
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: test_users_by_locale
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: metabase_internal_pg
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: SELECT COALESCE(locale, 'unknown') AS locale, COUNT(*) AS n FROM core_user GROUP BY locale ORDER BY n DESC
|
||||
parameter_mappings: []
|
||||
display: bar
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
@@ -0,0 +1,29 @@
|
||||
_meta:
|
||||
kind: card
|
||||
id: 47
|
||||
slug: top_clientes
|
||||
synced_at: '2026-04-13T10:49:59Z'
|
||||
remote_updated_at: '2026-04-13T10:49:59.882916Z'
|
||||
_refs:
|
||||
database: sample_database
|
||||
collection: null
|
||||
payload:
|
||||
description: Top 10 clientes por gasto total
|
||||
archived: false
|
||||
enable_embedding: false
|
||||
query_type: native
|
||||
name: top_clientes
|
||||
type: question
|
||||
dataset_query:
|
||||
lib/type: mbql/query
|
||||
database: sample_database
|
||||
stages:
|
||||
- lib/type: mbql.stage/native
|
||||
native: "SELECT P.NAME AS cliente,\n P.EMAIL AS email,\n COUNT(O.ID) AS num_compras,\n ROUND(SUM(O.TOTAL),\
|
||||
\ 2) AS total_gastado\n FROM PEOPLE P\n JOIN ORDERS O ON O.USER_ID = P.ID\n GROUP BY P.NAME, P.EMAIL\n ORDER BY\
|
||||
\ total_gastado DESC\n LIMIT 10"
|
||||
parameter_mappings: []
|
||||
display: table
|
||||
collection_preview: true
|
||||
visualization_settings: {}
|
||||
parameters: []
|
||||
Reference in New Issue
Block a user