@metabase/cli 0.5.8 → 0.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-collection-DIrpeq9O.mjs → add-collection-B6_b7Z0h.mjs} +3 -3
- package/dist/{alert-DuUreVMq.mjs → alert-CaOd6Sye.mjs} +7 -7
- package/dist/{alerts-C7vJ-NAI.mjs → alerts-B4XDd_EG.mjs} +6 -6
- package/dist/api-key-BEyGzjhr.mjs +13 -0
- package/dist/{append-v3fakJOd.mjs → append-D4yRU3nt.mjs} +4 -4
- package/dist/{archive-TBPRGm7s.mjs → archive-B0wPQhnH.mjs} +3 -3
- package/dist/{archive-DwVbn3FG.mjs → archive-B4KdkRj1.mjs} +3 -3
- package/dist/{archive-BrGj2yoP.mjs → archive-BTpXIs7W.mjs} +3 -3
- package/dist/{archive-Cy6RUJaD.mjs → archive-BTsVi373.mjs} +3 -3
- package/dist/{archive-5pjvTser.mjs → archive-BkCFPiWS.mjs} +3 -3
- package/dist/{archive-Bt8fwInI.mjs → archive-BxN7gbKa.mjs} +4 -4
- package/dist/{archive-CuygjxgQ.mjs → archive-CSt4KxhB.mjs} +3 -3
- package/dist/{archive-D299FxXt.mjs → archive-DJT5Du9l.mjs} +3 -3
- package/dist/{archive-DdPaXaJo.mjs → archive-DoZ8HBxg.mjs} +4 -4
- package/dist/{archive-CyhH-395.mjs → archive-btZAAdMv.mjs} +3 -3
- package/dist/{archive-CmhV_hlP.mjs → archive-jtNM7hhn.mjs} +3 -3
- package/dist/{archive-BEhhmkTO.mjs → archive-pMSD0Cou.mjs} +3 -3
- package/dist/{auth-B63Hfuwg.mjs → auth-BtrN725t.mjs} +5 -5
- package/dist/{branches-BM0L124r.mjs → branches-D4Lwau0h.mjs} +3 -3
- package/dist/{breaking-VMUrgVVE.mjs → breaking-DH9tr0ug.mjs} +5 -5
- package/dist/{broken-BbpNq5WG.mjs → broken-DiT2Ww1u.mjs} +6 -6
- package/dist/{bulk-discard-values-Cohox-Zb.mjs → bulk-discard-values-D7jD6GjV.mjs} +5 -5
- package/dist/{bulk-edit-B9-XH592.mjs → bulk-edit-DsetARSf.mjs} +3 -3
- package/dist/{bulk-rescan-values-CsWKirZw.mjs → bulk-rescan-values-DSUVmXSh.mjs} +4 -4
- package/dist/{bulk-sync-schema-CorpcAjz.mjs → bulk-sync-schema-n5Qe7UnU.mjs} +4 -4
- package/dist/{cancel-iGUVm1h2.mjs → cancel-oFccoFiE.mjs} +3 -3
- package/dist/{cancel-task-DWiicb_t.mjs → cancel-task-kpJZ4G2I.mjs} +2 -2
- package/dist/card-Bnkg5z4G.mjs +25 -0
- package/dist/{cards-D6jWz0N9.mjs → cards-BCU56A8s.mjs} +4 -4
- package/dist/{ci-BQKTyiRi.mjs → ci-DfbKRU5x.mjs} +2 -2
- package/dist/cli.mjs +52 -47
- package/dist/{client-Ba61gEcn.mjs → client-BvjSFQ8P.mjs} +27 -42
- package/dist/collection-CXYDfvsX.mjs +21 -0
- package/dist/{collection-namespace-D0_-6eWp.mjs → collection-namespace-lQLOPUbc.mjs} +1 -1
- package/dist/{content-translation-B57aHSuc.mjs → content-translation-CsRsYA5Q.mjs} +3 -3
- package/dist/{copy-D-VIVVB1.mjs → copy-7kyXaQVn.mjs} +4 -4
- package/dist/{copy-BeD_fk5J.mjs → copy-CR8wSNpp.mjs} +4 -4
- package/dist/{copy-flags-BcW9weVX.mjs → copy-flags-Bgy3sSFg.mjs} +1 -1
- package/dist/{create-CP9lrYE4.mjs → create-BAxf_Wqm.mjs} +2 -2
- package/dist/{create-BlmRvuQg.mjs → create-BIgILG1P.mjs} +3 -3
- package/dist/{create-HNchuWpj.mjs → create-BMe3ZtQi.mjs} +3 -3
- package/dist/{create-DybrZHV-.mjs → create-BZ9x1_Dm.mjs} +2 -2
- package/dist/{create-zALsdMhF.mjs → create-BZ_tLyVg.mjs} +2 -2
- package/dist/{create-DcDyXL4g.mjs → create-BewmenPL.mjs} +2 -2
- package/dist/{create-C6c-clLK.mjs → create-BhHZBIc4.mjs} +3 -3
- package/dist/{create-BURh8kHp.mjs → create-BrFgRgjY.mjs} +3 -3
- package/dist/{create-MmZVmRsH.mjs → create-C1CwTQjk.mjs} +2 -2
- package/dist/{create-CGiSOtIR.mjs → create-Cx47jTQ9.mjs} +3 -3
- package/dist/{create-Bw9DAq_x2.mjs → create-CxZe8ghH2.mjs} +5 -5
- package/dist/{create-B--aPIbp.mjs → create-D6FGsFnV.mjs} +2 -2
- package/dist/{create-DF7nC9qW.mjs → create-DG9NIdWy.mjs} +2 -2
- package/dist/{create-_wex54m1.mjs → create-DHJ75ufg.mjs} +2 -2
- package/dist/{create-lHqpAdxg.mjs → create-DVYRfN1s.mjs} +3 -3
- package/dist/{create-DQOapeeI.mjs → create-DYf1fYsW.mjs} +3 -3
- package/dist/{create-DMtlDzrE.mjs → create-DaspEGaN.mjs} +3 -3
- package/dist/{create-Dm8BvbsU.mjs → create-Ddt8jkGe.mjs} +2 -2
- package/dist/{create-branch-C8arQT4M.mjs → create-branch-CSqKpG-X.mjs} +2 -2
- package/dist/{create-D44fg_iT.mjs → create-gD1BKkjH.mjs} +2 -2
- package/dist/{csv-CFabsH6l.mjs → csv-CEQ5iHiR.mjs} +4 -4
- package/dist/{current-task-GG6JqfGp.mjs → current-task-Cwn-A02w.mjs} +2 -2
- package/dist/dashboard-BQMAwgQv.mjs +35 -0
- package/dist/data-action-BOyBN50C.mjs +24 -0
- package/dist/data-app-CTxlD3Sa.mjs +39 -0
- package/dist/{data-app-Blz61mG5.mjs → data-app-Cglgbj_E.mjs} +1 -1
- package/dist/{data-app-BUW-HlUo.mjs → data-app-bl88oUla.mjs} +27 -14
- package/dist/data-app-project-C1V4_8k5.mjs +155 -0
- package/dist/{db-DSj2I1X9.mjs → db-DjrLLqDW.mjs} +8 -8
- package/dist/{delete-Dkwk2mZH.mjs → delete-B3zIJHbp.mjs} +4 -4
- package/dist/{delete-YKX2HilI.mjs → delete-B8wPN6Mi.mjs} +4 -4
- package/dist/{delete-CsgkbmBy.mjs → delete-BecCd6_I.mjs} +4 -4
- package/dist/{delete-Cx75BsN6.mjs → delete-CA8N6OSh.mjs} +4 -4
- package/dist/{delete-AF64p0xG.mjs → delete-CYPidCqb.mjs} +4 -4
- package/dist/{delete-CnGb4QIm.mjs → delete-Crc2lguC.mjs} +4 -4
- package/dist/{delete-CxL5okLN.mjs → delete-DvHo5Dau.mjs} +4 -4
- package/dist/{delete-C6N_Aj78.mjs → delete-auLsOacz.mjs} +4 -4
- package/dist/{delete-D_l7FRE6.mjs → delete-rBkGuteA.mjs} +4 -4
- package/dist/{delete-runtime-BUbOQx5I.mjs → delete-runtime-Bxy6qAqZ.mjs} +2 -2
- package/dist/{delete-table-CubRk-5H.mjs → delete-table-CWo5Azjp.mjs} +4 -4
- package/dist/{dependencies-W2dxsCpF.mjs → dependencies-B5rZybIE.mjs} +5 -5
- package/dist/dependency-BCvsKkvF.mjs +15 -0
- package/dist/{dependency-BPCRTBKd.mjs → dependency-DdeyH8m5.mjs} +1 -1
- package/dist/{dependents-B4V8pDYq.mjs → dependents-DTokHohZ.mjs} +6 -6
- package/dist/{dirty-DKj4ScBN.mjs → dirty-DJzqGN8R.mjs} +3 -3
- package/dist/{discard-values-5l91z3Dy.mjs → discard-values-Z0Aaau-z.mjs} +5 -5
- package/dist/document-DaQNhYhh.mjs +20 -0
- package/dist/{download-DRxR3yGi.mjs → download-CUNQkaWC.mjs} +2 -2
- package/dist/{eid-B6JYogNC.mjs → eid-CA9nIsPk.mjs} +2 -2
- package/dist/{entry-flags-6Y0fdYbG.mjs → entry-flags-CsbT7fHf.mjs} +1 -1
- package/dist/{events-CE80dTib.mjs → events-CtMOLbVW.mjs} +4 -4
- package/dist/{execute-C9foK2IU.mjs → execute-BFKWsB4U.mjs} +3 -3
- package/dist/{export-B8QyoPWP.mjs → export-DsbEWoLo.mjs} +3 -3
- package/dist/{export-flags-DvdxpRMt.mjs → export-flags-DkbYlWlE.mjs} +1 -1
- package/dist/{export-preflight-BQbwxyoJ.mjs → export-preflight-TRzdLXI_.mjs} +2 -2
- package/dist/field-BnSUwI5l.mjs +21 -0
- package/dist/{fields-TE3PnmwW.mjs → fields-Cf-yzUqO.mjs} +4 -4
- package/dist/{filter-flags-DAUmdUwa.mjs → filter-flags-B5jGUuHb.mjs} +1 -1
- package/dist/{fks-B41Re5dt.mjs → fks-BL7aqSz3.mjs} +5 -5
- package/dist/generate-actions-D8iT2Vx_.mjs +38 -0
- package/dist/generate-queries-Cmo2IFAd.mjs +41 -0
- package/dist/generate-schema-Hubesglp.mjs +34 -0
- package/dist/{get-DguRhloC.mjs → get-10d6M3WX.mjs} +2 -2
- package/dist/{get-DvPgnqAA.mjs → get-45g97RD0.mjs} +2 -2
- package/dist/{get-DJeeXbwj.mjs → get-B0AwjMgu.mjs} +3 -3
- package/dist/{get-CtRJUybv.mjs → get-B6uK0K5I.mjs} +3 -3
- package/dist/{get-DeiC05Lm.mjs → get-B7I96VF7.mjs} +3 -3
- package/dist/{get-BcWr6U0n.mjs → get-BPrKH_VC.mjs} +2 -2
- package/dist/{get-BJgBsiEK.mjs → get-BRfgDBX1.mjs} +5 -5
- package/dist/{get-uWk0JKvF.mjs → get-B_1SDjVE.mjs} +4 -4
- package/dist/{get-BscyItLF.mjs → get-BsLJ6NN4.mjs} +3 -3
- package/dist/{get-PLIbg3Vy.mjs → get-C1d4sGGj.mjs} +3 -3
- package/dist/{get-sjhoDJyB.mjs → get-C4TSvV8x.mjs} +5 -5
- package/dist/{get-Cjk-A9dQ.mjs → get-CHmUuPoY.mjs} +3 -3
- package/dist/{get-BAGQ-bvt.mjs → get-CNwSqJ34.mjs} +3 -3
- package/dist/{get-CCTRO18v.mjs → get-CORcDYjE.mjs} +4 -4
- package/dist/{get-DG5fPl-S.mjs → get-CQx83tws.mjs} +4 -4
- package/dist/{get-m-vpr7GN.mjs → get-CkiiPNoS.mjs} +3 -3
- package/dist/{get-CU6AWbqL.mjs → get-Cvl3jefC.mjs} +3 -3
- package/dist/{get-CefCrGWy.mjs → get-DAsNzVI7.mjs} +3 -3
- package/dist/{get-DbZDp2ve.mjs → get-DIYDn-tm.mjs} +3 -3
- package/dist/{get-Ck0cRNyr.mjs → get-DUvEGkvw.mjs} +4 -4
- package/dist/{get-3XwqrjxC.mjs → get-O81o3nAv.mjs} +3 -3
- package/dist/{get-run-DnKCnvUa.mjs → get-run-uEQGMjmi.mjs} +4 -4
- package/dist/{get-BrhIHZYg.mjs → get-xMWLwAHj.mjs} +3 -3
- package/dist/git-sync-CswhluG_.mjs +29 -0
- package/dist/glossary-Cb37yiw3.mjs +14 -0
- package/dist/{graph-B2YkV2oX.mjs → graph-BKuSPVVZ.mjs} +4 -4
- package/dist/{group-D1nGaEXW.mjs → group-DxaqX3Gg.mjs} +1 -1
- package/dist/{has-remote-changes-ChMSjhmC.mjs → has-remote-changes-BUCHJZqQ.mjs} +2 -2
- package/dist/{import-CNpN9iS0.mjs → import-B-ekaPHP.mjs} +3 -3
- package/dist/{is-dirty-Bud2wuxQ.mjs → is-dirty-BGcu7D5c.mjs} +2 -2
- package/dist/{items-B1DXzdwg.mjs → items-vDPpkZUK.mjs} +3 -3
- package/dist/{library-8G0s5VLO.mjs → library-n-3eu6WW.mjs} +5 -5
- package/dist/{list-z4iqffgl.mjs → list-BIOCkt1A.mjs} +4 -4
- package/dist/{list-CAAvhl9h.mjs → list-BSQPBkVu.mjs} +3 -3
- package/dist/{list-tHzgEkzv.mjs → list-BiXIUvBg.mjs} +5 -5
- package/dist/{list-BVz0N0g_.mjs → list-BoOFUEYh.mjs} +3 -3
- package/dist/{list-Dk3upD11.mjs → list-BtENqZIq.mjs} +5 -5
- package/dist/{list-DAdWd8gn.mjs → list-C8a6WeMs.mjs} +3 -3
- package/dist/{list-BeaA7gQ7.mjs → list-CADlvzKj.mjs} +3 -3
- package/dist/{list-DjfY80vj.mjs → list-Ci8Y9AdJ.mjs} +3 -3
- package/dist/{list-Ckqu41Zx.mjs → list-CoM1L7ZK.mjs} +3 -3
- package/dist/{list-CAZHyhd5.mjs → list-D-zjbHfR.mjs} +3 -3
- package/dist/{list-BSvQ0AT_.mjs → list-D5yxCOsl.mjs} +3 -3
- package/dist/{list-0aX638ov.mjs → list-DJAlAVuS.mjs} +5 -5
- package/dist/{list-B2PbnXp4.mjs → list-DMdRy6Cx.mjs} +4 -4
- package/dist/{list-DpyIV41y.mjs → list-DU2dKd2T.mjs} +4 -4
- package/dist/{list-CcfGHN19.mjs → list-J5FxC72O.mjs} +3 -3
- package/dist/{list-BJasizCe.mjs → list-JWWHtIMj.mjs} +3 -3
- package/dist/{list-CO62N1eD.mjs → list-PvFvPn0p.mjs} +3 -3
- package/dist/{list-D1WO7lxP.mjs → list-Qy-5LvDC.mjs} +4 -4
- package/dist/{list-DX5SmBCQ.mjs → list-UJ3nPrrD.mjs} +3 -3
- package/dist/{list-mRSKPKoO.mjs → list-e8h2S-3y.mjs} +3 -3
- package/dist/{list-DZLGnsAK.mjs → list-jfxTNTSm.mjs} +3 -3
- package/dist/{list-CPwy-AEn.mjs → list-mkXqkfck.mjs} +8 -12
- package/dist/{list-JqIFAXpw.mjs → list-nd6-vgOU.mjs} +3 -3
- package/dist/{login-muOdP15h.mjs → login-DcneUyj9.mjs} +4 -4
- package/dist/{logout-Z0_gSSM4.mjs → logout-wA2-ebUy.mjs} +2 -2
- package/dist/{measure-CTF4qqiE.mjs → measure-BICKq4Ud.mjs} +6 -6
- package/dist/nano-id-qEgGloYk.mjs +55 -0
- package/dist/{notification-Bj45MgWm.mjs → notification-Ec1Jo0Oc.mjs} +1 -1
- package/dist/{parameter-values-to5u_-2n.mjs → parameter-values-d_zi14dw.mjs} +3 -3
- package/dist/{parse-id-CbF7zxGv.mjs → parse-id-DKKwr4c8.mjs} +1 -1
- package/dist/{path-B-0S-9i2.mjs → path-Cn1xCJb_.mjs} +4 -4
- package/dist/{poll-zB3cX0Kq.mjs → poll-BGWVry_U.mjs} +1 -1
- package/dist/{preflight-Dgj2yyY_.mjs → preflight-Beuxqhhf.mjs} +1 -1
- package/dist/{publish-tKh9tJeh.mjs → publish-C89wo-cw.mjs} +3 -3
- package/dist/{pulse-DhddeMMG.mjs → pulse-BWs9tqVG.mjs} +1 -1
- package/dist/{query-o1Z2dgtw.mjs → query-L29u5CEu.mjs} +4 -4
- package/dist/{query-B4xK9j0u.mjs → query-ja91JN10.mjs} +4 -4
- package/dist/{remapping-DT305P-k.mjs → remapping-B8aqlkSk.mjs} +3 -3
- package/dist/{remove-collection-Bsme1OBA.mjs → remove-collection-LbKh838S.mjs} +3 -3
- package/dist/{render-Df56xOPJ.mjs → render-C96TStlT.mjs} +1 -1
- package/dist/{replace-C3PQwvfl.mjs → replace-B9Cyb9q2.mjs} +4 -4
- package/dist/{requirement-check-qqRkRGcN.mjs → requirement-check-XJCPOfWw.mjs} +2 -2
- package/dist/{rescan-values-C0P0upEB.mjs → rescan-values-Ca4FVr2Q.mjs} +4 -4
- package/dist/{rescan-values-CGN4bjyB.mjs → rescan-values-uxZ22Z0c.mjs} +3 -3
- package/dist/{run-C_IZfmQ7.mjs → run-B4zwhVuB.mjs} +404 -85
- package/dist/{run-bVD66LrU.mjs → run-BQvsDYzx.mjs} +3 -3
- package/dist/{run-ZRY5wy4x.mjs → run-CtGMVO3W.mjs} +4 -4
- package/dist/{run-BaEBHum8.mjs → run-DskhDpUQ.mjs} +4 -4
- package/dist/{runs-DWm1pIdP.mjs → runs-C0s-CfQE.mjs} +5 -5
- package/dist/{runtime-Dd2uBKqN.mjs → runtime-B8leBJ1G.mjs} +6 -5
- package/dist/scaffold-BdrbFYhc.mjs +54 -0
- package/dist/{schema-DoELV3FT.mjs → schema-8tGj8t5W.mjs} +2 -2
- package/dist/{schema-tables-DGyHJnJX.mjs → schema-tables-DZRvTRLf.mjs} +5 -5
- package/dist/{schemas-7w9MPZcZ.mjs → schemas-yiE-cMoI.mjs} +4 -4
- package/dist/{search-BZh0BwZ9.mjs → search-1-5z-NQO.mjs} +4 -4
- package/dist/{search-CyyySVTz.mjs → search-Cdd2cDNA.mjs} +4 -4
- package/dist/{segment--JCnZCgL.mjs → segment-DcLtYcgq.mjs} +6 -6
- package/dist/{send-c4FpapMf.mjs → send-I5nk7MpB.mjs} +3 -3
- package/dist/{set-active-BexM75_s.mjs → set-active-DrgsPOnr.mjs} +2 -2
- package/dist/{set-data-actions-BnrX6ARh.mjs → set-data-actions-C-TNEnTJ.mjs} +3 -3
- package/dist/{set-enabled-Np4xqFA_.mjs → set-enabled-Co0jIMn0.mjs} +5 -5
- package/dist/{set-sensitivity-DDzrkjdv.mjs → set-sensitivity-DCOxoynX.mjs} +3 -3
- package/dist/{set-_puxfyaP.mjs → set-vigeEoz9.mjs} +2 -2
- package/dist/{setting-BGK1uRxm.mjs → setting-DqHsywkM.mjs} +4 -4
- package/dist/{setup-BCliYRAt.mjs → setup-2EJT5aTc.mjs} +2 -2
- package/dist/{skill-list-4LagdTq5.mjs → skill-list-Duqt2jXs.mjs} +1 -1
- package/dist/{skills-CoXIflBw.mjs → skills-n1IpS3pA.mjs} +3 -3
- package/dist/{skills-PULUh2VV.mjs → skills-xJsQWYll.mjs} +3 -3
- package/dist/{slug-COdwq63O.mjs → slug-9m4PXe-s.mjs} +1 -1
- package/dist/snippet-CDLpUxOv.mjs +19 -0
- package/dist/{stash-d3FtnE2F.mjs → stash-C7VstG6F.mjs} +3 -3
- package/dist/{status-BJTdBEN4.mjs → status-BclmIIUO.mjs} +3 -3
- package/dist/{status-CJLd6Uk6.mjs → status-DZh35kON.mjs} +2 -2
- package/dist/{subscription-Dpq45fMP.mjs → subscription-DaEZk3Am.mjs} +6 -6
- package/dist/{subscriptions-Cu4km2CN.mjs → subscriptions-DcOtdHen.mjs} +6 -6
- package/dist/{summary-3Av5251t.mjs → summary-yoqD8lKK.mjs} +3 -3
- package/dist/{sync-schema-BYJuUBsG.mjs → sync-schema-C7mvw4JY.mjs} +4 -4
- package/dist/{sync-schema-BNHt8S3P.mjs → sync-schema-QcmZUpbc.mjs} +4 -4
- package/dist/table-CSv2nzuP.mjs +26 -0
- package/dist/{table-DFbkLSgK.mjs → table-CcUdjp8F.mjs} +1 -1
- package/dist/{table-selector-flags-BiA8p56s.mjs → table-selector-flags-FNPxRc9B.mjs} +2 -2
- package/dist/{timeline-event-BLBqSAjH.mjs → timeline-event-B3bnxvSU.mjs} +6 -6
- package/dist/timeline-xSDfBYEA.mjs +21 -0
- package/dist/transform-D5ugnljj.mjs +28 -0
- package/dist/{transform-CKeLIqoc.mjs → transform-drjCAqQs.mjs} +1 -1
- package/dist/transform-job-C3uL7HVt.mjs +22 -0
- package/dist/{transform-tag-CETHXuAi.mjs → transform-tag-Dh_xkEHJ.mjs} +5 -5
- package/dist/transform-test-DO4J2dGZ.mjs +16 -0
- package/dist/{transforms-CstSQgQ-.mjs → transforms-BhycY9Dy.mjs} +5 -5
- package/dist/{transport-D74axlBJ.mjs → transport-B4wfgpqB.mjs} +3 -3
- package/dist/{tree-BDhm4E_W.mjs → tree-C0Jqbvr7.mjs} +2 -2
- package/dist/{unpublish-BNBSxZFl.mjs → unpublish-0erfDFu-.mjs} +3 -3
- package/dist/{unreferenced-B2nDcQ7m.mjs → unreferenced-CHJuU079.mjs} +5 -5
- package/dist/{update-BkFy2BV_.mjs → update-BAl0aZsq.mjs} +4 -4
- package/dist/{update-BGFGng3a.mjs → update-BGCKUTtV.mjs} +4 -4
- package/dist/{update-pzu78yZB.mjs → update-BHz5uxTe.mjs} +3 -3
- package/dist/{update-DRw_610p.mjs → update-BPaXLS7J.mjs} +4 -4
- package/dist/{update-Cpd1tKqr.mjs → update-BYfjNqm0.mjs} +3 -3
- package/dist/{update-BMHPp3nt.mjs → update-Bzbst6T5.mjs} +3 -3
- package/dist/{update-ByBqo1if.mjs → update-C7_YQxNg.mjs} +4 -4
- package/dist/{update-CWzmrGS_.mjs → update-C8Ec4fCx.mjs} +3 -3
- package/dist/{update-BS-E7QLh.mjs → update-CBcKfzne.mjs} +4 -4
- package/dist/{update-BenGrugz.mjs → update-CR1zzVES.mjs} +4 -4
- package/dist/{update-BA0NxInb.mjs → update-CZkKz3PD.mjs} +4 -4
- package/dist/{update-DU3jpGps.mjs → update-CjKfz61h.mjs} +3 -3
- package/dist/{update-B6xWuJqk.mjs → update-DAl3J-6n.mjs} +3 -3
- package/dist/{update-CFLJWHOT.mjs → update-DSlAN-t5.mjs} +3 -3
- package/dist/{update-DrvDC_0m2.mjs → update-Dh1X_b9e2.mjs} +3 -3
- package/dist/{update-DxLypq9G.mjs → update-DnGjFqwP.mjs} +6 -6
- package/dist/{update-B9iHHoJB.mjs → update-DqN3ikiq.mjs} +4 -4
- package/dist/{update-DT8KwBxO.mjs → update-Is5yboYO.mjs} +4 -4
- package/dist/{update-dashcard-BU3Wqcnf.mjs → update-dashcard-B8s5t0jG.mjs} +3 -3
- package/dist/{update-DKcPzoG9.mjs → update-ujP9d00H.mjs} +3 -3
- package/dist/{upgrade-Cq89D4Oe.mjs → upgrade-Dc43HJun.mjs} +2 -2
- package/dist/upload-DIiiLP23.mjs +13 -0
- package/dist/{upload-INQHve86.mjs → upload-DWwwFANs.mjs} +3 -3
- package/dist/{upload-CmwO6anj.mjs → upload-xXTXZQsW.mjs} +1 -1
- package/dist/{uuid-BNJKaQGB.mjs → uuid-BNZQ6Dyb.mjs} +2 -2
- package/dist/{validate-query-CQ4UPpZX.mjs → validate-query-37KgmRbb.mjs} +1 -1
- package/dist/{values-BVtqwRlR.mjs → values-thjqrbtC.mjs} +3 -3
- package/dist/{verify-BSlj7S_E.mjs → verify-CLObQxZk.mjs} +3 -3
- package/dist/{verify-Bp9ZyPgX.mjs → verify-CqJPc-DW.mjs} +3 -3
- package/dist/{verify-BwodYH0C.mjs → verify-DNhhRy4T.mjs} +3 -3
- package/dist/{wait-DZclBI3D.mjs → wait-DxeRAukN.mjs} +4 -4
- package/dist/{wait-flags-CmIfm6_U.mjs → wait-flags-P5MIy4fp.mjs} +2 -2
- package/dist/{window-BoW2xWwm.mjs → window-CI_QD04s.mjs} +1 -1
- package/dist/{yaml-BthVUNj3.mjs → yaml-BtI8iDba.mjs} +16 -7
- package/package.json +1 -1
- package/skill-data/core/SKILL.md +1 -1
- package/skill-data/data-action/SKILL.md +2 -3
- package/skill-data/data-app/SKILL.md +64 -45
- package/skill-data/data-app/template/.env.local.example +1 -0
- package/skill-data/data-app/template/README.md +16 -7
- package/skill-data/data-app/template/gitignore +0 -1
- package/skill-data/data-app/template/package.json +1 -2
- package/skill-data/data-app/template/src/metabase.actions.ts +3 -0
- package/skill-data/data-app/template/src/metabase.queries.ts +3 -0
- package/skill-data/data-app/template/src/metabase.schema.ts +3 -0
- package/skill-data/data-app/template/src/theme.ts +3 -1
- package/skill-data/data-app-actions/SKILL.md +43 -23
- package/skill-data/data-app-data/SKILL.md +86 -64
- package/skill-data/data-app-filters/SKILL.md +3 -3
- package/skill-data/data-app-ui/SKILL.md +12 -4
- package/skill-data/git-sync/SKILL.md +4 -6
- package/skill-data/transform/SKILL.md +1 -1
- package/dist/api-key-Cia6SHQ9.mjs +0 -13
- package/dist/card-C-KsmoJW.mjs +0 -25
- package/dist/collection-DsNRlVcN.mjs +0 -21
- package/dist/create-D-Eu1nBe.mjs +0 -37
- package/dist/dashboard-BRQtw_1e.mjs +0 -35
- package/dist/data-action-Bm6QMyV0.mjs +0 -24
- package/dist/data-app-DtW2i2SD.mjs +0 -41
- package/dist/data-app-project-CHYcJRrU.mjs +0 -58
- package/dist/delete-ClT1ROrM.mjs +0 -40
- package/dist/dependency-B0KmVz2u.mjs +0 -15
- package/dist/document--zYZP-u3.mjs +0 -20
- package/dist/field-Bk09crKC.mjs +0 -21
- package/dist/git-sync-DMyH3Y85.mjs +0 -29
- package/dist/glossary-CcRGJaVi.mjs +0 -14
- package/dist/scaffold-BnT99dhY.mjs +0 -50
- package/dist/set-bundle-B-qAvkDo.mjs +0 -40
- package/dist/snippet-Czzma-M2.mjs +0 -19
- package/dist/table-CwfF6ZTZ.mjs +0 -26
- package/dist/timeline-C4WCMzDX.mjs +0 -21
- package/dist/transform-job-SQ57QOlQ.mjs +0 -22
- package/dist/transform-jxF8cjNA.mjs +0 -28
- package/dist/transform-test-MlVjTlKo.mjs +0 -16
- package/dist/typed-schema-BZkv_z2f.mjs +0 -45
- package/dist/update-DrfAOlkf.mjs +0 -36
- package/dist/upload-DbDFl9qT.mjs +0 -13
|
@@ -1,50 +1,72 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-app-actions
|
|
3
|
-
description: Make a Metabase data app write data —
|
|
3
|
+
description: Make a Metabase data app write data — a table action that inserts, updates or deletes a row of a published table, defined with `defineAction` in `src/metabase.actions.ts`, and the `useAction` hook from `@metabase/embedding-sdk-react/data-app` behind a form or a button, with inputs typed from each parameter, the server's error shown as it comes, and every affected query refreshed. Triggers — "a form that saves a row", "a button that updates a record", "delete an entry from the app", "submit doesn't refresh the list", "the action fails in the app". Reads are `data-app-data`.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
requires: [dataApps]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Writes in a data app
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
A data app writes through **table actions**: an insert, update or delete of one row of a table published to the Library, by its primary key. It defines each one in `src/metabase.actions.ts`, one export per action:
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
3. Pass `actions.<name>` from it to `useAction`.
|
|
12
|
+
```ts
|
|
13
|
+
import { defineAction } from "@metabase/embedding-sdk-react/data-app";
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
import { schema } from "./metabase.schema";
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
export const updateOrder = defineAction({
|
|
18
|
+
entityId: "J2mXq8sLb0vT5nYcW4kRd",
|
|
19
|
+
kind: "row/update",
|
|
20
|
+
table: schema.tables.orders,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `kind` is `row/create`, `row/update` or `row/delete`; `table` is a table of `schema` (`data-app-data`). The table needs exactly one primary key, and its database needs data actions turned on (_Data actions on the database_): settle both before writing the export. Show the user the table and kind and add it once they agree; a request that already names the write ("let me add a note") is that agreement.
|
|
25
|
+
- `entityId` comes from `mb nano-id`, never invented; keep it when editing the export. The export's name is the action's name in Metabase.
|
|
26
|
+
- There are no query actions and no SQL: a write a table action can't do (a computed value, several rows, a row matched by another column) is out of reach for the app — say so. Never copy an action from a data actions collection.
|
|
27
|
+
- To drop an action, delete its export.
|
|
28
|
+
|
|
29
|
+
The dev preview runs the action without saving it; Metabase runs it once the app is released (`data-app`, _Release_).
|
|
30
|
+
|
|
31
|
+
## Data actions on the database
|
|
32
|
+
|
|
33
|
+
Before the first action on a database, read its toggle: `mb db get <db-id> --full --json --profile <name> | jq '.settings["database-enable-actions"]'` (`<db-id>` from `mb db list --profile <name> --json`, or `mb table get <table-id> --json --profile <name> | jq .db_id` once `src/metabase.schema.ts` gives the table's `id`). Anything but `true`, an unset `null` included, means it's off, and every action on that database fails with `Actions are not enabled.`, in the preview and in Metabase. Then ask with `AskUserQuestion` ("Data actions are off on <database>. Turning them on lets anyone with access to its actions write to it."), offering:
|
|
34
|
+
|
|
35
|
+
- **Turn them on now**: run `mb db set-data-actions <db-id> true --profile <name>`, then read the toggle again.
|
|
36
|
+
- **I'll turn them on**: the user does it in Admin → Databases → the database ("Allow data actions that use this database to be run"); wait for them, then read the toggle again before going on.
|
|
37
|
+
- **No writes**: build the app without actions, and tell the user which features that leaves out.
|
|
38
|
+
|
|
39
|
+
Never turn the toggle on without that yes.
|
|
19
40
|
|
|
20
41
|
## The hook
|
|
21
42
|
|
|
22
43
|
```tsx
|
|
23
44
|
import { useAction } from "@metabase/embedding-sdk-react/data-app";
|
|
24
|
-
import {
|
|
45
|
+
import { updateOrder } from "../metabase.actions";
|
|
25
46
|
|
|
26
|
-
const { execute, isExecuting, result, error, reset } = useAction(
|
|
47
|
+
const { execute, isExecuting, result, error, reset } = useAction(updateOrder);
|
|
27
48
|
```
|
|
28
49
|
|
|
29
50
|
- **Import it from `/data-app`.** The main `@metabase/embedding-sdk-react` entry exports the general SDK `useAction`, which takes raw ids and isn't typed from the definition. Write no generics: the definition types `execute`'s keys and values.
|
|
30
51
|
- `execute(params)` resolves to the response body; on failure it both throws and sets `error`. It resolves to `null` without sending anything while the SDK is still starting, so guard a call that can happen at mount. It never runs on its own and has no `enabled`: return early in the handler to skip it.
|
|
31
52
|
- `isExecuting` is true until it settles: disable the trigger and show progress, so a double click can't send twice.
|
|
32
|
-
- `result` is the last response, `null` before the first call
|
|
53
|
+
- `result` is the last response, `null` before the first call: `{ "created-row": <the new row> }` for an insert, `{ "rows-updated": <n> }` for an update, `{ "rows-deleted": <n> }` for a delete. `reset()` clears `result` and `error`, for example when the user dismisses a message.
|
|
33
54
|
|
|
34
55
|
## A form
|
|
35
56
|
|
|
36
57
|
```tsx
|
|
37
58
|
export function NoteForm({ orderId, onSaved }: { orderId: number; onSaved: () => Promise<void> }) {
|
|
38
|
-
const { execute, isExecuting, error } = useAction(
|
|
59
|
+
const { execute, isExecuting, error } = useAction(updateOrder);
|
|
39
60
|
const [note, setNote] = useState("");
|
|
40
61
|
const [isValid, setIsValid] = useState(false);
|
|
41
62
|
|
|
42
63
|
async function onSubmit(event: FormEvent<HTMLFormElement>) {
|
|
43
64
|
event.preventDefault();
|
|
44
65
|
try {
|
|
45
|
-
await execute({
|
|
66
|
+
await execute({ id: orderId, note }); // keys are column names, in lowercase
|
|
46
67
|
await onSaved(); // the parent refetches what the write changed
|
|
47
68
|
setNote("");
|
|
69
|
+
setIsValid(false);
|
|
48
70
|
} catch {
|
|
49
71
|
// shown from `error`
|
|
50
72
|
}
|
|
@@ -66,25 +88,23 @@ export function NoteForm({ orderId, onSaved }: { orderId: number; onSaved: () =>
|
|
|
66
88
|
}
|
|
67
89
|
```
|
|
68
90
|
|
|
69
|
-
**
|
|
91
|
+
**Parameters.** The keys `execute` takes are the table's column names in lowercase (`CREATED_AT` becomes `created_at`; names already in lowercase stay as they are), each typed from its field's `jsType` in `src/metabase.schema.ts`, and all optional in the type. Pick each input from `jsType`, never from the name — a column called `email` with `jsType: "string"` is still `type="text"`.
|
|
70
92
|
|
|
71
93
|
| `jsType` | Input |
|
|
72
94
|
| --------- | ---------------------------------------------------------- |
|
|
73
|
-
| `string` | `type="text"
|
|
95
|
+
| `string` | `type="text"`; a `<textarea>` for long text such as a note |
|
|
74
96
|
| `number` | `type="number"`, read with `valueAsNumber` |
|
|
75
97
|
| `boolean` | a checkbox or switch |
|
|
76
98
|
| `Date` | `type="date"`, or `datetime-local` when a time is expected |
|
|
77
99
|
| `unknown` | `type="text"`, converted at the call |
|
|
78
100
|
|
|
79
|
-
**
|
|
80
|
-
|
|
81
|
-
- **Insert** (`row/create`): every column but an auto-increment key. `result["created-row"]` holds the new row's parameter columns, its key among them.
|
|
82
|
-
- **Update** (`row/update`): the key and every other column, `required` on each `NOT NULL` one without a default. Start the form from the row's current values, read by the query on screen, and send them all. A `null` is dropped, so an update can't clear a column.
|
|
101
|
+
- **Insert** (`row/create`): every column but an auto-increment key and the columns the database fills when the form leaves them out, such as a `created_at` or `status` with a default. `mb table get <id> --include fields --full --json` gives each field's `database_required` and `database_default`. `result["created-row"]` holds the new row, its key among them.
|
|
102
|
+
- **Update** (`row/update`): the key and the columns to change. An edit form starts from the row's current values, read by the query on screen, and sends them all; a button that sets one column (mark as done) sends only the key and that column. A fixed value such as `"done"` comes from the column's values (`mb field values <field-id> --profile <name>`), never a guess. A `null` is dropped, so an update can't clear a column.
|
|
83
103
|
- **Delete** (`row/delete`): the key only. Ask the viewer to confirm first.
|
|
84
104
|
|
|
85
|
-
**Validation** is `required` on each
|
|
105
|
+
**Validation** is `required` on the key of an update or delete and on each `NOT NULL` column without a default in an insert, and nothing else — no length, range or format checks of your own. Disable submit from the browser's verdict, `form.checkValidity()`, never from hand-rolled checks. Anything stricter comes back from the server.
|
|
86
106
|
|
|
87
|
-
**Errors.** `error` is `{ status?, data: { message?, errors? }, isCancelled }` — read it without a cast.
|
|
107
|
+
**Errors.** `error` is `{ status?, data: { message?, errors? }, isCancelled }` — read it without a cast. Refusals and constraint errors are 400s whose `data.message` carries the server's text (`Sorry, the row you're trying to update doesn't exist`): show it as it comes, in a `white-space: pre-wrap` element, since driver messages span lines — never "Something went wrong", `String(error)` or a friendlier paraphrase. `error.data.errors?.[parameter]`, when present, goes beside its field (`aria-invalid` on the input).
|
|
88
108
|
|
|
89
109
|
## Refresh
|
|
90
110
|
|
|
@@ -97,9 +117,9 @@ After a write succeeds, refetch every query on screen it could have changed: `aw
|
|
|
97
117
|
|
|
98
118
|
## When it doesn't work
|
|
99
119
|
|
|
100
|
-
1. Log `result`, `error` and the object passed to `execute`: every key is a
|
|
120
|
+
1. Log `result`, `error` and the object passed to `execute`: every key is a lowercase column name, every value matches its `jsType`.
|
|
101
121
|
2. `execute` resolved to `null` and nothing was sent: it ran before the SDK started.
|
|
102
122
|
3. The screen doesn't update: see _Refresh_.
|
|
103
|
-
4.
|
|
123
|
+
4. It works in the preview but not in Metabase: the app was released without running `mb data-app generate-actions` (`data-app`, _Release_).
|
|
104
124
|
|
|
105
|
-
Then
|
|
125
|
+
Then release the app (`data-app`, _Release_).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-app-data
|
|
3
|
-
description: Give a Metabase data app its data —
|
|
3
|
+
description: Give a Metabase data app its data — `src/metabase.schema.ts` from `mb data-app generate-schema`, questions over the Library's published tables and metrics as `defineQuery` exports in `src/metabase.queries.ts`, their entity IDs from `mb nano-id`, and the `useMetabaseQuery` and `useMetabaseQueryObject` hooks that run them, with runtime filter clauses, sorting and aggregation. Triggers — "show revenue by month in my data app", "list customers in the app", "add a KPI", "a chart of orders by category", "regenerate the schema". Creating and releasing the app is `data-app`; filter controls are `data-app-filters`; writes are `data-app-actions`; chart choice and sizing are `data-app-ui`.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
requires: [dataApps]
|
|
6
6
|
---
|
|
@@ -9,40 +9,68 @@ requires: [dataApps]
|
|
|
9
9
|
|
|
10
10
|
Before changing an existing app, pass the checks in `data-app`, _An existing project_: the template's config and factory, and React 19.
|
|
11
11
|
|
|
12
|
-
A data app runs only the questions and actions
|
|
12
|
+
A data app runs only the questions and actions it defines; its viewers can read nothing else. So every piece of data starts in its source:
|
|
13
13
|
|
|
14
|
-
1.
|
|
15
|
-
2.
|
|
16
|
-
3. Pass
|
|
14
|
+
1. Fetch `src/metabase.schema.ts` (below).
|
|
15
|
+
2. Define a question in `src/metabase.queries.ts` (below) or an action in `src/metabase.actions.ts` (`data-app-actions`).
|
|
16
|
+
3. Pass the export to a hook. The dev preview runs it at once; Metabase runs it once the app is released (`data-app`, _Release_).
|
|
17
17
|
|
|
18
18
|
## Sources: the semantic layer only
|
|
19
19
|
|
|
20
|
-
An app reads only what the user curated in the Library. Metabase refuses a question
|
|
20
|
+
An app reads only what the user curated in the Library, and `src/metabase.schema.ts` holds exactly that. Metabase refuses a question that breaks these rules:
|
|
21
21
|
|
|
22
|
-
- **Tables published to the Library**, and nothing else:
|
|
23
|
-
- **Metrics in the Library
|
|
24
|
-
- **No other question as a source** — not
|
|
25
|
-
- **MBQL
|
|
22
|
+
- **Tables published to the Library**, and nothing else: the source table, every table reached through a foreign key column, and the tables behind its segments and measures.
|
|
23
|
+
- **Metrics in the Library**, as aggregations, and the segments and measures of published tables. Prefer one that matches the concept over rebuilding it with filters and thresholds of your own.
|
|
24
|
+
- **No other question as a source** — not one of the app's own, a model or a metric. Every question starts from a published table.
|
|
25
|
+
- **One stage of MBQL**, never native SQL, with no explicit joins and no custom columns: reach another table through a foreign key column, and compute in the app.
|
|
26
26
|
|
|
27
27
|
When the app needs a table or metric the Library lacks, stop: name what's missing and ask the user to publish the table or move the metric into the Library. Don't publish it yourself unless the user says to, and never work around the gap with an unpublished table, a copy of the data, or SQL.
|
|
28
28
|
|
|
29
|
+
## `src/metabase.schema.ts`
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd <repo> && mb data-app generate-schema <slug> --profile <name>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
From the repository root, this writes `data_apps/<slug>/src/metabase.schema.ts`: the Library's published tables with their fields, segments and measures, and the Library's metrics, each keyed by its camelCased name, with its numeric ID. It exports `schema` (`import { schema } from "./metabase.schema"`). Fetch it again after the user publishes a table or changes its metadata, then `npm run typecheck`, which catches code still using a renamed or removed field. Never edit the file.
|
|
36
|
+
|
|
37
|
+
The numeric IDs are that instance's, so the dev preview runs against it alone; a production build runs each question by its `entityId` instead, on every instance the app is imported to.
|
|
38
|
+
|
|
29
39
|
## Questions
|
|
30
40
|
|
|
31
|
-
|
|
41
|
+
`src/metabase.queries.ts` holds one export per question:
|
|
32
42
|
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
```ts
|
|
44
|
+
import {
|
|
45
|
+
aggregations,
|
|
46
|
+
breakout,
|
|
47
|
+
defineQuery,
|
|
48
|
+
orderBy,
|
|
49
|
+
} from "@metabase/embedding-sdk-react/data-app";
|
|
50
|
+
|
|
51
|
+
import { schema } from "./metabase.schema";
|
|
52
|
+
|
|
53
|
+
const orders = schema.tables.orders;
|
|
54
|
+
|
|
55
|
+
export const revenueByMonth = defineQuery({
|
|
56
|
+
entityId: "Vh3kq0wYc8TnS2aJm1LxR",
|
|
57
|
+
source: orders,
|
|
58
|
+
aggregations: [aggregations.sum(orders.fields.total, { name: "revenue" })],
|
|
59
|
+
breakouts: [breakout(orders.fields.createdAt, { unit: "month" })],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const latestReviews = defineQuery({
|
|
63
|
+
entityId: "pW9dE4uNq7Zb1fGhK3sTy",
|
|
64
|
+
source: schema.tables.reviews,
|
|
65
|
+
orderBys: [orderBy(schema.tables.reviews.fields.createdAt, "desc")],
|
|
66
|
+
limit: 20,
|
|
67
|
+
});
|
|
44
68
|
```
|
|
45
69
|
|
|
70
|
+
- `source` is a table of `schema`; `aggregations`, `breakouts`, `filters`, `orderBys`, `limit` and `fields` (the columns to keep) take its fields, its segments and measures, and the metrics of `schema.metrics` as aggregations (`aggregations: [schema.metrics.revenue]`). A field that isn't the table's, or an operator its type doesn't take, fails to compile.
|
|
71
|
+
- The export's name is the question's name in Metabase, as written (`customerList`).
|
|
72
|
+
- Each `entityId` comes from `mb nano-id` (`mb nano-id --count <n>` for several), never invented or copied. Keep an export's `entityId` when you edit it: a new one replaces the question with another.
|
|
73
|
+
|
|
46
74
|
Plan the questions from what the app shows and picks from — each chart, KPI, table and filter option list needs one, and several panels may share one. Each takes one of two shapes:
|
|
47
75
|
|
|
48
76
|
- **Aggregated**, when the breakdown is fixed: revenue by month, top products. Runtime clauses can then name only the columns it returns, its breakouts and aggregations.
|
|
@@ -51,38 +79,11 @@ Plan the questions from what the app shows and picks from — each chart, KPI, t
|
|
|
51
79
|
Also:
|
|
52
80
|
|
|
53
81
|
- A question filtered at runtime has no `limit` of its own: it would apply before the filters. Put the limit in the hook. A question nothing filters, such as "the 20 latest reviews", keeps its sort and limit.
|
|
54
|
-
-
|
|
55
|
-
- `display` and `visualization_settings` show only in Metabase; the app picks its own chart type.
|
|
56
|
-
- Nothing in the app's collection is archived, public or embedded. To drop a question, move it out (`mb card update <id> --body '{"collection_id":<other>}'`), then archive it.
|
|
82
|
+
- To drop a question, delete its export.
|
|
57
83
|
|
|
58
|
-
|
|
84
|
+
A result column's `name` keys the rows and names the column in runtime clauses: a field's `name` in `src/metabase.schema.ts`, in the database's own case (`CREATED_AT` here, `created_at` on Postgres), or an aggregation's — `count`, `sum`, or the `name` you gave it. Never take one from SQL:
|
|
59
85
|
|
|
60
|
-
|
|
61
|
-
mb data-app typed-schema <slug> --out src/metabase.ts
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Run it after **every** change to the app's collection, then `npm run typecheck`, which catches code still using a renamed or removed column. Never edit the file. It names every question and action by entity ID, so it works unchanged on every instance the app is synced to.
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
export const queries = {
|
|
68
|
-
revenueByMonth: defineQuery({
|
|
69
|
-
source: {
|
|
70
|
-
type: "card",
|
|
71
|
-
entityId: "…",
|
|
72
|
-
name: "Revenue by month",
|
|
73
|
-
columns: [
|
|
74
|
-
{ type: "column", name: "CREATED_AT", displayName: "Created At: Month", jsType: "Date", semanticType: "type/CreationTimestamp" },
|
|
75
|
-
{ type: "column", name: "sum", displayName: "Sum of Total", jsType: "number", semanticType: "type/Currency" },
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
}),
|
|
79
|
-
};
|
|
80
|
-
export const actions = { setOrderNote: defineAction({ action: { id: "…", parameters: [ … ] } }) };
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
A column's `name` keys the rows and names the column in runtime clauses. Take it from this file, never from SQL:
|
|
84
|
-
|
|
85
|
-
- A column reached through a foreign key keeps its own name (`CATEGORY`, not `PRODUCTS__via__PRODUCT_ID__CATEGORY`), and a named aggregation keeps its name.
|
|
86
|
+
- A column reached through a foreign key keeps its own name (`CATEGORY`, not `PRODUCTS__via__PRODUCT_ID__CATEGORY`).
|
|
86
87
|
- A foreign key that Metabase displays as a name returns that name as an extra column: `USER_ID` comes with a `NAME` column whose `displayName` is "User ID". Show `NAME`; filter by `USER_ID`.
|
|
87
88
|
- A `Date` column's values arrive as ISO strings.
|
|
88
89
|
|
|
@@ -90,15 +91,36 @@ A column's `name` keys the rows and names the column in runtime clauses. Take it
|
|
|
90
91
|
|
|
91
92
|
```tsx
|
|
92
93
|
import { useMetabaseQuery } from "@metabase/embedding-sdk-react/data-app";
|
|
93
|
-
import {
|
|
94
|
+
import { revenueByMonth } from "../metabase.queries";
|
|
94
95
|
|
|
95
|
-
const { data, error, refetch } = useMetabaseQuery(
|
|
96
|
-
const rows = data?.rows ?? []; // row.CREATED_AT, row.
|
|
96
|
+
const { data, error, refetch } = useMetabaseQuery(revenueByMonth);
|
|
97
|
+
const rows = data?.rows ?? []; // row.CREATED_AT, row.revenue, typed from jsType
|
|
97
98
|
```
|
|
98
99
|
|
|
99
100
|
- Rows are objects keyed by column `name`. Never index them by position or cast them, and guard `null` values.
|
|
100
|
-
- `data` is `null` until the first answer, and stays `null` while the query is held back with `enabled: false` — show the before-a-choice state then. Otherwise `
|
|
101
|
-
- `error` is `unknown
|
|
101
|
+
- `data` is `null` until the first answer, and stays `null` while the query is held back with `enabled: false` — show the before-a-choice state then. Otherwise `isLoading` is true while a run is in flight (it stays false while held back), and `data.rows.length === 0` is empty.
|
|
102
|
+
- `error` is `unknown`. A refused or failed query sets it to the response, `{ status, data }`, whose `data` is the server's message or an object with a `message`; anything else is an `Error`. Read it with one helper, which narrows without a cast, and render its message in the panel as it comes:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
export function errorMessage(error: unknown): string {
|
|
106
|
+
if (typeof error === "object" && error !== null && "data" in error) {
|
|
107
|
+
const { data } = error;
|
|
108
|
+
if (typeof data === "string") {
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
if (
|
|
112
|
+
typeof data === "object" &&
|
|
113
|
+
data !== null &&
|
|
114
|
+
"message" in data &&
|
|
115
|
+
typeof data.message === "string"
|
|
116
|
+
) {
|
|
117
|
+
return data.message;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return error instanceof Error ? error.message : String(error);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
102
124
|
- Call each hook once, in the highest component that needs the data, and pass the result down. Never call a hook in a loop or a condition.
|
|
103
125
|
|
|
104
126
|
## Charts: `useMetabaseQueryObject`
|
|
@@ -110,7 +132,7 @@ import { StaticQuestion, type MetabaseCard } from "@metabase/embedding-sdk-react
|
|
|
110
132
|
import { useMetabaseQueryObject } from "@metabase/embedding-sdk-react/data-app";
|
|
111
133
|
import { useMemo } from "react";
|
|
112
134
|
|
|
113
|
-
const { query, isLoading, error } = useMetabaseQueryObject(
|
|
135
|
+
const { query, isLoading, error } = useMetabaseQueryObject(revenueByMonth);
|
|
114
136
|
const card = useMemo(() => ({ query, visualization: "line" }) satisfies MetabaseCard, [query]);
|
|
115
137
|
|
|
116
138
|
// PanelError and Spinner are the app's own components
|
|
@@ -119,7 +141,7 @@ if (isLoading || !query) return <Spinner />;
|
|
|
119
141
|
return <StaticQuestion card={card} height={360} />;
|
|
120
142
|
```
|
|
121
143
|
|
|
122
|
-
- Always pass `visualization`:
|
|
144
|
+
- Always pass `visualization`: without one Metabase picks a default, often a table. Which chart, its settings and its size: `data-app-ui`.
|
|
123
145
|
- Build `card` with `useMemo` keyed on `query`: a new object re-runs the question.
|
|
124
146
|
- Render `error` wherever this hook is used: reading only `query` makes a failed question look like endless loading.
|
|
125
147
|
|
|
@@ -131,7 +153,7 @@ Both hooks take a second argument: one object with the clauses the UI changes, a
|
|
|
131
153
|
import { aggregations, filter, orderBy } from "@metabase/embedding-sdk-react/data-app";
|
|
132
154
|
|
|
133
155
|
const [start, end] = range; // from DateRangePopover (data-app-filters)
|
|
134
|
-
const { query } = useMetabaseQueryObject(
|
|
156
|
+
const { query } = useMetabaseQueryObject(orderRows, {
|
|
135
157
|
filters:
|
|
136
158
|
start && end ? [filter({ type: "column", name: "CREATED_AT" }, "between", [start, end])] : [],
|
|
137
159
|
aggregations: [aggregations.sum({ type: "column", name: "TOTAL" }, { name: "revenue" })],
|
|
@@ -140,7 +162,7 @@ const { query } = useMetabaseQueryObject(queries.orderRows, {
|
|
|
140
162
|
});
|
|
141
163
|
```
|
|
142
164
|
|
|
143
|
-
- A column is `{ type: "column", name }` with a `name
|
|
165
|
+
- A column is `{ type: "column", name }` with a result column's `name`, or a field of `schema`; a wrong name, or an operator its type doesn't take, fails to compile. A date breakout takes a `unit` (`day`, `week`, `month`, `quarter`, `year`).
|
|
144
166
|
|
|
145
167
|
| Column type | Operators |
|
|
146
168
|
| ----------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -149,12 +171,12 @@ const { query } = useMetabaseQueryObject(queries.orderRows, {
|
|
|
149
171
|
| date | `=`, `!=`, `>`, `>=`, `<`, `<=`, `between`, `time-interval`, `is-null`, `not-null` |
|
|
150
172
|
| boolean | `=`, `is-null`, `not-null` |
|
|
151
173
|
|
|
152
|
-
- `filter(...)` takes one value: `filter(col, "=", [a, b])` compiles but is not an IN filter, and several filters AND together. So a filter picks one value or All; for a multi-select, ask the user whether a single choice will do.
|
|
174
|
+
- `filter(...)` takes one value (`filter(col, "=", 42)`): `filter(col, "=", [a, b])` compiles but is not an IN filter, and several filters AND together. So a filter picks one value or All; for a multi-select, ask the user whether a single choice will do.
|
|
153
175
|
- Text operators are case-sensitive, with no option to change it: say so in the search box's placeholder.
|
|
154
|
-
- `time-interval` (`[-30, "day"]`, `[0, "year"]` for this year) is relative to when the query runs: a fixed window belongs in the
|
|
176
|
+
- `time-interval` (`[-30, "day"]`, `[0, "year"]` for this year) is relative to when the query runs: a fixed window belongs in the definition, not the hook.
|
|
155
177
|
- On a rows question, aggregate with any of `aggregations.count`, `sum`, `avg`, `median`, `min`, `max`, `distinct`, naming each result (`{ name: "revenue" }`) to order or read it by — two unnamed results of one operator collide, and generated names such as `sum_2` aren't stable. Never aggregate an aggregated question at runtime: a sum over its rows is wrong for distinct counts, averages, ratios and levels such as MRR. A runtime filter only picks its rows. So a date filter on it offers presets of whole, complete buckets at the question's own grain (Last month, Last 12 months on a month question), each range from the first bucket's start to the last bucket's start, and no Custom range; a KPI shows one bucket, as `scalar` (a `smartscalar` filtered to one bucket loses its comparison), with no All time. A filter on a column needs a question broken out by that column too; its All is no clause when the panel shows that column (a series per value), and otherwise a second question without that breakout, both hooks called and switched with `enabled`. When a request needs more, say so.
|
|
156
178
|
- A sort the user picks: map each choice to a column explicitly (`{ revenue: "revenue", orders: "order_count" }`) rather than passing the user's value through.
|
|
157
179
|
- `enabled: false` holds the query back, for example until the user picks an item.
|
|
158
180
|
- Write the arrays inline (spreads are fine): the hooks compare by content, so a new array per render doesn't refetch. A clauses object built outside the call needs `as const`, or `aggregations` loses the tuple type `breakouts` need; a shared `ReturnType<typeof filter>[]` built with `push` breaks the operator types the same way.
|
|
159
181
|
|
|
160
|
-
The controls that feed these clauses are `data-app-filters`. When the data is in place,
|
|
182
|
+
The controls that feed these clauses are `data-app-filters`. When the data is in place, release the app (`data-app`, _Release_).
|
|
@@ -26,7 +26,7 @@ Before any control, write one row per filter: the question that gives its option
|
|
|
26
26
|
## Values and options
|
|
27
27
|
|
|
28
28
|
- Every filter starts at **All**, except a KPI's own date control (above). Keep it as `"all"` in state and send it as no clause (`[]`), except on an aggregated question whose panel doesn't show the filtered column, where All is its own question (`data-app-data`, _Runtime clauses_); treat `""`, `null` and `undefined` the same way. In a Yes/No/All filter, Yes and No each filter (`true`, `false`), and only All sends nothing.
|
|
29
|
-
- Options come at runtime from their own question
|
|
29
|
+
- Options come at runtime from their own question (`data-app-data`), broken out on the filtered column — never hardcoded unless the user gave a closed list. Dedupe them from its rows, and keep the label apart from the value.
|
|
30
30
|
- Filter by a stable raw value (an id) and show its label; never filter by a display label when an id exists, and never feed free text into an exact-id filter.
|
|
31
31
|
- All stays selectable while options load, come back empty or fail; don't disable the control. When fresh options no longer hold the selected value, reset to All:
|
|
32
32
|
|
|
@@ -40,7 +40,7 @@ useEffect(() => {
|
|
|
40
40
|
|
|
41
41
|
## Entities: a searchable combobox
|
|
42
42
|
|
|
43
|
-
Any
|
|
43
|
+
Any filter control whose options come from a question — an id shown as a name, a category, anything that can grow — is one searchable combobox, even while it's short. Picking a row in a list the page already shows (a customer table driving that customer's details) is not a filter control: the row click is the picker. A `<select>` is only for a short closed list the user gave. Prefer the app's component library or a small established combobox package; hand-roll only a small one. Either way:
|
|
44
44
|
|
|
45
45
|
- Click or focus opens the list at once, before any typing; search matches labels, not ids.
|
|
46
46
|
- All is always an option, and picking an option stores its raw value.
|
|
@@ -92,4 +92,4 @@ const lastCompleteMonths = (n: number): [string, string] => {
|
|
|
92
92
|
|
|
93
93
|
## Check
|
|
94
94
|
|
|
95
|
-
For every visible filter except a KPI's own date control: All runs the unfiltered question, or its All question; its options come from a question; each option changes every panel the contract says it reaches, and no other; a preset bar ends with Custom unless it filters an aggregated question; and no scope has two date controls. Search the filter controls for `<select` and `type="date"` — an action form keeps its date inputs. Then
|
|
95
|
+
For every visible filter except a KPI's own date control: All runs the unfiltered question, or its All question; its options come from a question; each option changes every panel the contract says it reaches, and no other; a preset bar ends with Custom unless it filters an aggregated question; and no scope has two date controls. Search the filter controls for `<select` and `type="date"` — an action form keeps its date inputs. Then release the app (`data-app`, _Release_).
|
|
@@ -22,7 +22,7 @@ Everything here runs inside the sandbox, the same in the dev preview as in Metab
|
|
|
22
22
|
## What the app shows
|
|
23
23
|
|
|
24
24
|
- Only what Metabase returned, or deterministic transforms of it: no sample data, invented KPIs, trends, statuses, or claims such as "real-time" or "at risk" the data doesn't support. A section no question supports is left out.
|
|
25
|
-
- Don't read a `rate`, `score`, `margin` or `percent` column as a percentage or threshold — no `%`, `* 100`, colors or stars — unless its `semanticType` in `src/metabase.ts`, or the user, says so.
|
|
25
|
+
- Don't read a `rate`, `score`, `margin` or `percent` column as a percentage or threshold — no `%`, `* 100`, colors or stars — unless its field's `semanticType` in `src/metabase.schema.ts`, or the user, says so.
|
|
26
26
|
- Every panel has a loading state, its error, and an empty state for no rows — never an empty slot or a stale value.
|
|
27
27
|
- Label with names, not ids; currency to two decimals, counts as integers; a `null` breakout is "Unknown". A trend needs several points: never a sparkline from one value. Cap long lists with a limit, pages or a scroll area.
|
|
28
28
|
|
|
@@ -38,7 +38,14 @@ Everything here runs inside the sandbox, the same in the dev preview as in Metab
|
|
|
38
38
|
| `navigator.geolocation` and other device APIs | Nothing. |
|
|
39
39
|
| Key, input, composition and clipboard listeners (`keydown`, `paste`, `input`, …) on `window` or `document` | A React handler (`onKeyDown`, `onPaste`, …) on your own element. |
|
|
40
40
|
|
|
41
|
-
**External APIs.** A raw `fetch` reaches only the origins in the app's `allowed_hosts`, exact or with a `*.` subdomain wildcard
|
|
41
|
+
**External APIs.** A raw `fetch` reaches only the origins in the app's `allowed_hosts`, exact or with a `*.` subdomain wildcard, listed in `data_app.yaml` beside `package.json`:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
allowed_hosts:
|
|
45
|
+
- https://api.example.com
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The preview reads the list there: restart `npm run dev` after changing it. Metabase applies it once the app is released (`data-app`, _Release_). Never list the Metabase URL. In Metabase the same list governs `<iframe src>` and native `<form action>` submits, and the target must allow framing; the preview blocks both. Use `<form onSubmit>` with `preventDefault`: a native submit navigates the app away.
|
|
42
49
|
|
|
43
50
|
## Layout
|
|
44
51
|
|
|
@@ -77,7 +84,7 @@ export function AppError({ message }: SdkErrorComponentProps) {
|
|
|
77
84
|
| `StaticQuestion` | A chart, KPI or table without drill-through — the default. |
|
|
78
85
|
| `InteractiveQuestion` | One meant to be explored: drill-through, chart switching; pass `isSaveEnabled={false}`. |
|
|
79
86
|
|
|
80
|
-
Both take
|
|
87
|
+
Both take the `card` built from `useMetabaseQueryObject` (`data-app-data`). Dashboards and the authoring components (`CreateQuestion`, `CreateDashboardModal`, saving from the editor) don't work in an app: an app can't save content.
|
|
81
88
|
|
|
82
89
|
## A Metabase chart or your own
|
|
83
90
|
|
|
@@ -85,6 +92,7 @@ Ask "can Metabase draw this at all?", never "which looks closer to the design?"
|
|
|
85
92
|
|
|
86
93
|
- **Yes** — bar, line, area, combo, row, pie, scalar, smartscalar, gauge, progress, funnel, scatter, waterfall, boxplot, sankey, pivot, map, tables: render it with `useMetabaseQueryObject` and `StaticQuestion` (`data-app-data`). It keeps the instance's formatting, tooltips, theming and drill-through. Styling is never a reason to draw it yourself.
|
|
87
94
|
- **No**, or the user asked for a custom one — scorecards, timelines, calendar grids, one visual from several queries: draw it from `useMetabaseQuery` rows, with SVG or a chart library the app already has.
|
|
95
|
+
- A table the user picks a row from, to drive another panel, is drawn from `useMetabaseQuery` rows with a button per row: an SDK question reports no row click.
|
|
88
96
|
- A KPI is `scalar`, `smartscalar`, `gauge` or `progress` — on a question filtered at runtime to one bucket, `scalar` (a `smartscalar` loses its comparison); put what Metabase doesn't draw (a caption, stars) beside it.
|
|
89
97
|
- `InteractiveQuestion`: pass `isSaveEnabled={false}`, and `title={false}` in a panel with its own heading. Children replace its layout: `<InteractiveQuestion card={card}><InteractiveQuestion.QuestionVisualization height={360} /></InteractiveQuestion>` is the chart alone.
|
|
90
98
|
|
|
@@ -120,4 +128,4 @@ Metabase mirrors each route to `/apps/<slug>/<path>`, and a reload there opens t
|
|
|
120
128
|
|
|
121
129
|
## Before handoff
|
|
122
130
|
|
|
123
|
-
`npm run dev` only transpiles: run `npm run typecheck` after every round of edits and fix what it reports, and report the result, errors grouped by cause. Search the changed files and fix what turns up: `card={{` (every `card` comes from `useMemo`), `row[0]` and `as unknown as` (rows are keyed by column name), `<select` for a list from a question (`data-app-filters`), `type="date"` and `new Date("` (a date string parsed as UTC) in a date filter, `* 100`
|
|
131
|
+
`npm run dev` only transpiles: run `npm run typecheck` after every round of edits and fix what it reports, and report the result, errors grouped by cause. Search the changed files and fix what turns up: `card={{` (every `card` comes from `useMemo`), `row[0]` and `as unknown as` (rows are keyed by column name), `<select` for a list from a question (`data-app-filters`), `type="date"` and `new Date("` (a date string parsed as UTC) in a date filter, and `* 100` or a number followed by `%` in rendered text (`grep -nE '[0-9}]\s*%'`, then skip CSS sizes such as `"100%"`). Read the diagnostics feed with every panel mounted, then release the app (`data-app`, _Release_).
|
|
@@ -7,7 +7,7 @@ requires: [remoteSync]
|
|
|
7
7
|
|
|
8
8
|
# git-sync (representations ↔ instance)
|
|
9
9
|
|
|
10
|
-
Metabase content (cards, dashboards, transforms, snippets, collections, …) can live in a git repo as YAML and round-trip in and out of a Metabase instance via the `git-sync` verbs. The instance is configured with a `remote-sync-*` settings block (URL, branch, token, type read-only/read-write); the CLI drives the sync tasks against `/api/ee/remote-sync/*`. Only flagged collections serialize, plus, unflagged: each data app's collection (with its app, `data_apps/<slug
|
|
10
|
+
Metabase content (cards, dashboards, transforms, snippets, collections, …) can live in a git repo as YAML and round-trip in and out of a Metabase instance via the `git-sync` verbs. The instance is configured with a `remote-sync-*` settings block (URL, branch, token, type read-only/read-write); the CLI drives the sync tasks against `/api/ee/remote-sync/*`. Only flagged collections serialize, plus, unflagged: each data app's collection (with its app, `data_apps/<slug>/`, authored in the repository: `data-app`), transforms (`remote-sync-transforms`), and snippets, data actions and glossary once the Library is synced. Everything else is local-only. Table and field metadata round-trips too, for Library-published tables in a flagged collection — see "Published table metadata" below.
|
|
11
11
|
|
|
12
12
|
The repo and the instance are two ends of the same state; what "push my changes" means depends on where the changes were made. If they were made **in the instance** (CLI verbs against a read-write instance — cards edited, transforms created, tables published, metadata written), "push my changes" / "save this to the repo" / "open a PR with these changes" means driving the instance's export to a branch (`stash` or `create-branch` + `export`) and opening the PR from that branch — not reconstructing the changes as files. If the workflow is **repo-first** (content YAML edited in the repo, the instance imports it), plain `git` against the repo is the way — but only in the serialized layout already there: files in paths or formats the serializer doesn't own are invisible to Metabase and never apply on import.
|
|
13
13
|
|
|
@@ -122,11 +122,9 @@ mb git-sync export-preflight --profile <n> --json # → {has_changes, clean, c
|
|
|
122
122
|
|
|
123
123
|
A dry run against the live remote branch, writing nothing. Read it between the state check and the export, and decide from the fields:
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
| `has_changes: true`, `reason: null` | The remote moved on. `clean` says whether a three-way merge would apply; `conflicts` names the entities changed on both sides; `summary` counts what a merge would fold in. | `clean: true`: `export --merge -m "..."`. `clean: false`: the conflicts need the user's call between the three options under "After a `conflict` task". A plain `export` ends in a `conflict` task, and so does `stash`: its new branch starts at the moved remote tip. |
|
|
129
|
-
| `reason: "history-rewritten"` | The remote was force-pushed or rebased, so there is no merge base. | Only `export --force` can push, and only with the user's explicit go-ahead; `force_push_casualties` is exactly what it would delete or overwrite. |
|
|
125
|
+
- **`has_changes: false`**: the remote has not moved past the last sync, or nothing has been synced yet — and then `force_push_casualties` is empty whatever the remote holds. `export -m "..."` applies as-is. Don't read empty casualties on a never-synced instance as leave to `--force`.
|
|
126
|
+
- **`has_changes: true`, `reason: null`**: the remote moved on. `clean` says whether a three-way merge would apply; `conflicts` names the entities changed on both sides; `summary` counts what a merge would fold in. `clean: true`: `export --merge -m "..."`. `clean: false`: the conflicts need the user's call between the three options under "After a `conflict` task". A plain `export` ends in a `conflict` task, and so does `stash`: its new branch starts at the moved remote tip.
|
|
127
|
+
- **`reason: "history-rewritten"`**: the remote was force-pushed or rebased, so there is no merge base. Only `export --force` can push, and only with the user's explicit go-ahead; `force_push_casualties` is exactly what it would delete or overwrite.
|
|
130
128
|
|
|
131
129
|
`force_push_casualties` is reported on every answer: it is the remote content a force push would discard instead of merging, so read it before ever passing `--force`. It is empty when nothing has been synced yet, yet `export --force` then replaces the remote's managed directories wholesale: check the remote before forcing a first export.
|
|
132
130
|
|
|
@@ -271,6 +271,6 @@ mb transform-job set-active false --profile <name> --json # disable every job a
|
|
|
271
271
|
|
|
272
272
|
<!-- /requires -->
|
|
273
273
|
|
|
274
|
-
Every job row carries `active`; it is `null` on a server that cannot switch jobs off, where every job runs on schedule.
|
|
274
|
+
Every job row carries `active`; it is `null` on a server that cannot switch jobs off, where every job runs on schedule. A job with `active: false` never runs on schedule, and a fresh install of a newer server starts the built-in jobs that no transform uses that way: before relying on one, check `active`, and turn it on only with the user's yes (`transform-job update <id> --body '{"active":true}'`, admin only).
|
|
275
275
|
|
|
276
276
|
`transform-job run` is fire-and-forget — it returns `{message, started, run_id}` immediately (both `null` when the server does not number job runs: the request was accepted and whether a run started is unsaid), with no per-job-run polling (no `--wait`). Most ad-hoc agent work is one-off `transform run`, not job authoring.
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-D1nGaEXW.mjs";
|
|
2
|
-
//#region src/commands/api-key/index.ts
|
|
3
|
-
var api_key_default = defineCommandGroup({
|
|
4
|
-
name: "api-key",
|
|
5
|
-
description: "Manage Metabase API keys",
|
|
6
|
-
subCommands: {
|
|
7
|
-
list: () => import("./list-mRSKPKoO.mjs").then((mod) => mod.default),
|
|
8
|
-
create: () => import("./create-Dm8BvbsU.mjs").then((mod) => mod.default),
|
|
9
|
-
delete: () => import("./delete-D_l7FRE6.mjs").then((mod) => mod.default)
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
//#endregion
|
|
13
|
-
export { api_key_default as default };
|
package/dist/card-C-KsmoJW.mjs
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-D1nGaEXW.mjs";
|
|
2
|
-
//#region src/commands/card/index.ts
|
|
3
|
-
var card_default = defineCommandGroup({
|
|
4
|
-
name: "card",
|
|
5
|
-
description: "Manage Metabase cards (questions, models, metrics)",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "mbql",
|
|
8
|
-
purpose: "author the dataset_query"
|
|
9
|
-
}, {
|
|
10
|
-
skill: "visualization",
|
|
11
|
-
purpose: "choose display and visualization_settings"
|
|
12
|
-
}],
|
|
13
|
-
subCommands: {
|
|
14
|
-
list: () => import("./list-DAdWd8gn.mjs").then((mod) => mod.default),
|
|
15
|
-
get: () => import("./get-3XwqrjxC.mjs").then((mod) => mod.default),
|
|
16
|
-
query: () => import("./query-B4xK9j0u.mjs").then((mod) => mod.default),
|
|
17
|
-
alerts: () => import("./alerts-C7vJ-NAI.mjs").then((mod) => mod.default),
|
|
18
|
-
create: () => import("./create-C6c-clLK.mjs").then((mod) => mod.default),
|
|
19
|
-
update: () => import("./update-BGFGng3a.mjs").then((mod) => mod.default),
|
|
20
|
-
verify: () => import("./verify-BSlj7S_E.mjs").then((mod) => mod.default),
|
|
21
|
-
archive: () => import("./archive-CuygjxgQ.mjs").then((mod) => mod.default)
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
//#endregion
|
|
25
|
-
export { card_default as default };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-D1nGaEXW.mjs";
|
|
2
|
-
//#region src/commands/collection/index.ts
|
|
3
|
-
var collection_default = defineCommandGroup({
|
|
4
|
-
name: "collection",
|
|
5
|
-
description: "Manage Metabase collections",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "core",
|
|
8
|
-
purpose: "collection ref forms and the transforms namespace"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
list: () => import("./list-CcfGHN19.mjs").then((mod) => mod.default),
|
|
12
|
-
get: () => import("./get-DvPgnqAA.mjs").then((mod) => mod.default),
|
|
13
|
-
items: () => import("./items-B1DXzdwg.mjs").then((mod) => mod.default),
|
|
14
|
-
tree: () => import("./tree-BDhm4E_W.mjs").then((mod) => mod.default),
|
|
15
|
-
create: () => import("./create-zALsdMhF.mjs").then((mod) => mod.default),
|
|
16
|
-
update: () => import("./update-DU3jpGps.mjs").then((mod) => mod.default),
|
|
17
|
-
archive: () => import("./archive-TBPRGm7s.mjs").then((mod) => mod.default)
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
//#endregion
|
|
21
|
-
export { collection_default as default };
|
package/dist/create-D-Eu1nBe.mjs
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { dt as outputFlags, ft as profileFlag, ot as connectionFlags, u as renderSummary } from "./cli.mjs";
|
|
2
|
-
import { t as defineMetabaseCommand } from "./runtime-Dd2uBKqN.mjs";
|
|
3
|
-
import { t as bodyInputFlags } from "./body-flags-AqKpN01Y.mjs";
|
|
4
|
-
import { r as DataAppCreateInput, t as DataApp } from "./data-app-BUW-HlUo.mjs";
|
|
5
|
-
import { t as dataAppView } from "./data-app-Blz61mG5.mjs";
|
|
6
|
-
//#region src/commands/data-app/create.ts
|
|
7
|
-
var create_default = defineMetabaseCommand({
|
|
8
|
-
meta: {
|
|
9
|
-
name: "create",
|
|
10
|
-
description: "Create a data app and its collection from JSON"
|
|
11
|
-
},
|
|
12
|
-
details: "The JSON body needs `name`, the slug. Optional: `display_name` (the slug by default), `description`, `allowed_hosts`, `enabled` (true by default), `bundle_path` and `version`. The app starts with an empty bundle; `mb data-app set-bundle` replaces it. The answer's `resource_collection_id` is the app's collection, where its questions and actions go. `mb data-app scaffold` copies the project template.",
|
|
13
|
-
skills: [{
|
|
14
|
-
skill: "data-app",
|
|
15
|
-
purpose: "how an app is created, built and published"
|
|
16
|
-
}],
|
|
17
|
-
requires: ["dataApp.create"],
|
|
18
|
-
args: {
|
|
19
|
-
...outputFlags,
|
|
20
|
-
...profileFlag,
|
|
21
|
-
...connectionFlags,
|
|
22
|
-
...bodyInputFlags
|
|
23
|
-
},
|
|
24
|
-
inputSchema: DataAppCreateInput,
|
|
25
|
-
outputSchema: DataApp,
|
|
26
|
-
examples: ["mb data-app create --body '{\"name\":\"sales-overview\",\"display_name\":\"Sales overview\"}'", "mb data-app create --file app.json --json"],
|
|
27
|
-
async run({ args, ctx, getClient, readBody }) {
|
|
28
|
-
const body = await readBody({
|
|
29
|
-
flag: args.body,
|
|
30
|
-
file: args.file
|
|
31
|
-
});
|
|
32
|
-
const created = await (await getClient()).dataApp.create(body);
|
|
33
|
-
renderSummary(created, dataAppView, `Created data app ${created.name} with collection ${created.resource_collection_id}.`, ctx);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
//#endregion
|
|
37
|
-
export { create_default as default };
|