@metabase/cli 0.5.12 → 0.5.14-alpha.cover-more-endpoints-for-mbcode.5fc0688
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-Bdnq6dfy.mjs → add-collection-DJzcGtj4.mjs} +1 -1
- package/dist/{alert-o2pHsbTh.mjs → alert-BMvkIX-V.mjs} +6 -6
- package/dist/{alerts-DS_uGWg-.mjs → alerts-CTyKwehF.mjs} +2 -2
- package/dist/{api-key-CfniVimJ.mjs → api-key-D23nm3yO.mjs} +3 -3
- package/dist/{append-DQCGJbx4.mjs → append-OiwbsoSf.mjs} +2 -2
- package/dist/{archive-Dku9fvdF.mjs → archive-5Iq32HEZ.mjs} +1 -1
- package/dist/{archive-DdnsMLHq.mjs → archive-6EMDIxGQ.mjs} +1 -1
- package/dist/{archive-BGHhmYW5.mjs → archive-B0cppwFz.mjs} +1 -1
- package/dist/{archive-CynNRHMt.mjs → archive-BJjGUSYK.mjs} +1 -1
- package/dist/{archive-DpT24NkM.mjs → archive-BXGTQk6v.mjs} +1 -1
- package/dist/{archive-DPETdLEn.mjs → archive-BlqPlRkv.mjs} +1 -1
- package/dist/{archive-CXsX26eE.mjs → archive-BrfFLutN.mjs} +1 -1
- package/dist/{archive-8xnKLGce.mjs → archive-CfA3hLMB.mjs} +1 -1
- package/dist/{archive-DoDF-x8G.mjs → archive-Cy2ErmV_.mjs} +1 -1
- package/dist/{archive-CNrp0Xu5.mjs → archive-DFRet_WE.mjs} +1 -1
- package/dist/{archive-BbXaLXFf.mjs → archive-DYRWEtgS.mjs} +1 -1
- package/dist/{archive-BhNU06xM.mjs → archive-wFufkogP.mjs} +1 -1
- package/dist/{auth-BQxyR2Ky.mjs → auth-DbvHl1mv.mjs} +4 -4
- package/dist/{branches-wa3G1T3B.mjs → branches-4nQwBRn-.mjs} +1 -1
- package/dist/{breaking-Cem7y-9U.mjs → breaking-B60w28TB.mjs} +1 -1
- package/dist/{broken-BkGLSqSO.mjs → broken-AYBRS3fU.mjs} +1 -1
- package/dist/{bulk-discard-values-BHryu-rZ.mjs → bulk-discard-values-BrGUZjx3.mjs} +1 -1
- package/dist/{bulk-edit-BPFITnRN.mjs → bulk-edit-DRKPfdvF.mjs} +1 -1
- package/dist/{bulk-rescan-values-DaeLpv7G.mjs → bulk-rescan-values-BRskV9Ug.mjs} +1 -1
- package/dist/{bulk-sync-schema-C_HNWZpZ.mjs → bulk-sync-schema-5tLPgo4m.mjs} +1 -1
- package/dist/{cancel-DiMIFIU9.mjs → cancel-CUusj5DZ.mjs} +1 -1
- package/dist/{cancel-task-0N0qb4_g.mjs → cancel-task-CPpxw9ro.mjs} +1 -1
- package/dist/{card-CWDFIZAt.mjs → card-Bb7HmgWr.mjs} +8 -8
- package/dist/{cards-Cu4jpvyn.mjs → cards-BtI858fw.mjs} +1 -1
- package/dist/{ci-CpsS8nSN.mjs → ci-B3RibgkB.mjs} +1 -1
- package/dist/cli.mjs +72 -43
- package/dist/{client-C8qLIQKB.mjs → client-Blk6DEyS.mjs} +402 -10
- package/dist/{collection-DF-kPs9K.mjs → collection-Co14NbD6.mjs} +7 -7
- package/dist/{content-translation-CfV9Ro5C.mjs → content-translation-52Eeb4ex.mjs} +2 -2
- package/dist/{copy-C8TUUSSh.mjs → copy-ByiA99ad.mjs} +1 -1
- package/dist/{copy-x3tre7ha.mjs → copy-fjdEbKEL.mjs} +1 -1
- package/dist/{create-BsbmZHOQ.mjs → create-BCE54UOt.mjs} +1 -1
- package/dist/{create-DcFQ2i9q.mjs → create-BCh91WW-.mjs} +1 -1
- package/dist/{create-6kfGBJ0u.mjs → create-BR9EwLe3.mjs} +1 -1
- package/dist/{create-CLxy2CyM.mjs → create-BSLCwcng.mjs} +1 -1
- package/dist/{create-axKIP4Lc.mjs → create-BT0AF_Uw.mjs} +1 -1
- package/dist/{create-DIRUAgUx.mjs → create-Btg4ubCp.mjs} +1 -1
- package/dist/{create-cXQtGG2g2.mjs → create-C4TeNsId2.mjs} +1 -1
- package/dist/{create-BEAJgGgc.mjs → create-COn_7kvg.mjs} +1 -1
- package/dist/{create-CtMZUIOK.mjs → create-CYXLviXa.mjs} +1 -1
- package/dist/{create-0nBN5L6G.mjs → create-D3jW-1Px.mjs} +2 -2
- package/dist/{create-Cj75IfaX.mjs → create-DTf9Ow_X.mjs} +1 -1
- package/dist/{create-DG1mYdU7.mjs → create-DiiSZf-a.mjs} +1 -1
- package/dist/{create-CCxsc9eK.mjs → create-Dsw3sj8m.mjs} +1 -1
- package/dist/{create-zuE-3HGv.mjs → create-Dv3EXqPH.mjs} +1 -1
- package/dist/{create-DS1ayvrI.mjs → create-O6NRnXN2.mjs} +1 -1
- package/dist/{create-DloJkv0t.mjs → create-OUmMh_VF.mjs} +1 -1
- package/dist/{create-BaIQ7zio.mjs → create-S_Zxue41.mjs} +1 -1
- package/dist/{create-lsrPI45N.mjs → create-UxNxOCly.mjs} +1 -1
- package/dist/{create-branch-CQHIvpmr.mjs → create-branch-Dr3xaBVZ.mjs} +1 -1
- package/dist/{create-B8qSd0YU.mjs → create-s4jqUEnS.mjs} +1 -1
- package/dist/{csv-zQ5stw4T.mjs → csv-C5fM43Kq.mjs} +2 -2
- package/dist/{current-task-CYWaDg5P.mjs → current-task-CVIxHhZD.mjs} +1 -1
- package/dist/{dashboard-CDNnQXAe.mjs → dashboard-C9c-3M-D.mjs} +11 -11
- package/dist/{data-action-DX_TuywQ.mjs → data-action-C686IOS8.mjs} +7 -7
- package/dist/{data-app-xTQWmzq-.mjs → data-app-BWj4SpLT.mjs} +12 -8
- package/dist/{database-C5ucihp3.mjs → database-BSETP2o-.mjs} +9 -2
- package/dist/{database-u_spHEa0.mjs → database-CCUXiXH_.mjs} +1 -1
- package/dist/{dataset-LJxNN6p5.mjs → dataset-a7Q_ocDR.mjs} +1 -1
- package/dist/{db-DBT-XMcs.mjs → db-DRZSHe1q.mjs} +7 -7
- package/dist/{delete-Du7t8vTU.mjs → delete-3Z4oIBdy.mjs} +1 -1
- package/dist/{delete-DiBfDyWE.mjs → delete-B7RBZmY_.mjs} +1 -1
- package/dist/{delete-lSNap63e.mjs → delete-BNVRCj6Q.mjs} +1 -1
- package/dist/{delete-DwbfrWC4.mjs → delete-BbCSnpU4.mjs} +1 -1
- package/dist/{delete-Du3GTGrS.mjs → delete-Byr5lvqH.mjs} +1 -1
- package/dist/{delete-FOycMM5r.mjs → delete-D-BxPS-t.mjs} +1 -1
- package/dist/{delete-CSlir440.mjs → delete-DueThJ9s.mjs} +1 -1
- package/dist/{delete-BHHw-4oq.mjs → delete-Qu3KFV4S.mjs} +1 -1
- package/dist/{delete-DAE74TK7.mjs → delete-dYG0WOzJ.mjs} +1 -1
- package/dist/{delete-table-Bn3lb-gW.mjs → delete-table-B7gWdygE.mjs} +1 -1
- package/dist/{dependencies-CHQOCCXo.mjs → dependencies-BxPGkZV0.mjs} +1 -1
- package/dist/{dependency-BQuI3QS1.mjs → dependency-lYZqkVhF.mjs} +5 -5
- package/dist/{dependents-COag5f7O.mjs → dependents-BNhX8duy.mjs} +1 -1
- package/dist/{dirty-DEsgt8QN.mjs → dirty-dcixQIPk.mjs} +1 -1
- package/dist/{discard-values-CkGnpZB3.mjs → discard-values-xbO7_GZP.mjs} +1 -1
- package/dist/{document-BY74mMhh.mjs → document-u01leBVr.mjs} +6 -6
- package/dist/{download-DMxWx04z.mjs → download-DOnWhcxJ.mjs} +1 -1
- package/dist/{eid-Dk7g1tz0.mjs → eid-C6mw8GTY.mjs} +1 -1
- package/dist/{embedding-sdk-DdFCPKMa.mjs → embedding-sdk-Fw8QM10p.mjs} +1 -1
- package/dist/{entry-flags-C63qXMR4.mjs → entry-flags-ZsxJgNQX.mjs} +1 -1
- package/dist/{events-DtN-OE9S.mjs → events-DbiGBvOO.mjs} +1 -1
- package/dist/{execute-CEbgEWvO.mjs → execute-Dut8mp4x.mjs} +1 -1
- package/dist/{export-CikXGxZP.mjs → export-DWm9KD8P.mjs} +2 -2
- package/dist/{export-preflight-2RkCrd6x.mjs → export-preflight-C8ZEm4LA.mjs} +1 -1
- package/dist/{field-SgHCyoPp.mjs → field-DgjHHVxm.mjs} +7 -7
- package/dist/{fields-30XWd-y0.mjs → fields-D83_FRxX.mjs} +1 -1
- package/dist/{fks-DbCuuP96.mjs → fks-CvHFfc9-.mjs} +1 -1
- package/dist/{generate-actions-PYrvMiLN.mjs → generate-actions-DdWCBLbI.mjs} +1 -1
- package/dist/{generate-queries-DlGaK7DB.mjs → generate-queries-D2-hoHbH.mjs} +1 -1
- package/dist/{generate-schema-DqXCs2iX.mjs → generate-schema-GzOla0-H.mjs} +1 -1
- package/dist/{get-titd1P4z.mjs → get-B6Oun1Wt.mjs} +1 -1
- package/dist/{get-BY2dpwUf.mjs → get-BHzgu9Vn.mjs} +1 -1
- package/dist/{get-BiJUoTTz.mjs → get-Bjs0bdq-.mjs} +1 -1
- package/dist/{get-f6LqvU79.mjs → get-Bpkaz8yl.mjs} +1 -1
- package/dist/{get-c5S1A1KR.mjs → get-C0Pou1iS.mjs} +1 -1
- package/dist/{get-B5IXr2LA.mjs → get-CE8XB5Ff.mjs} +1 -1
- package/dist/{get-DffZWqVG.mjs → get-CFnCAJ8A.mjs} +1 -1
- package/dist/{get-FQUF2V2a.mjs → get-CIiw9jYG.mjs} +1 -1
- package/dist/{get-C4V3bjdM.mjs → get-CJIMItSK.mjs} +1 -1
- package/dist/{get-CWt5CGo1.mjs → get-Cc7a55Qq.mjs} +1 -1
- package/dist/{get-CDy5pcag.mjs → get-Cix3ChSR.mjs} +1 -1
- package/dist/{get-DhzTEa4L.mjs → get-CpoEMbjo.mjs} +1 -1
- package/dist/{get-Dv5FwVWt.mjs → get-DAYyzoap.mjs} +1 -1
- package/dist/{get-DpJr1uPp.mjs → get-DDaAPHvY.mjs} +1 -1
- package/dist/{get-ChuHytCB.mjs → get-DLUfFObl.mjs} +1 -1
- package/dist/{get-DNtdPWc7.mjs → get-DlUJRAgf.mjs} +1 -1
- package/dist/{get-D2QYpaHG.mjs → get-Dp-pkw9c.mjs} +1 -1
- package/dist/{get-BPg5lW4z.mjs → get-DxvR0it8.mjs} +1 -1
- package/dist/{get-C3VvI9wW.mjs → get-JcggOTHQ.mjs} +1 -1
- package/dist/{get-DdtPtNWP.mjs → get-YTWSCyhk.mjs} +3 -3
- package/dist/{get-run-BdEVSnOR.mjs → get-run-CjhSF4xV.mjs} +1 -1
- package/dist/{get-DBnnbbJU.mjs → get-rzewe7MT.mjs} +1 -1
- package/dist/{get-DgVbjtv7.mjs → get-scHHOIDB.mjs} +2 -2
- package/dist/git-sync-NroY04HH.mjs +29 -0
- package/dist/{glossary-C2p6xe3-.mjs → glossary-DYZ_oNE1.mjs} +4 -4
- package/dist/{graph-Dp0sxg6m.mjs → graph-q-ho-Ckx.mjs} +1 -1
- package/dist/{has-remote-changes-CMMXEsXa.mjs → has-remote-changes-BPT3ro8x.mjs} +1 -1
- package/dist/{import-DZmfmoBw.mjs → import-csQ0DwW5.mjs} +2 -2
- package/dist/{is-dirty-DgrWNWdj.mjs → is-dirty-DC5HD7x9.mjs} +1 -1
- package/dist/{items-BvyV49xR.mjs → items-CY8s_m8H.mjs} +1 -1
- package/dist/{library-CMC67i7O.mjs → library-Cfs1NYLf.mjs} +4 -4
- package/dist/{list-rPk7T17I.mjs → list-B0UNVc3n.mjs} +1 -1
- package/dist/{list-BjIwIaNZ.mjs → list-BJNP1BQT.mjs} +1 -1
- package/dist/{list-B1NRLXpA.mjs → list-BRszRCfL.mjs} +1 -1
- package/dist/{list-XRvOaGPo.mjs → list-BTZjkrSb.mjs} +1 -1
- package/dist/{list-CcFPkvbL.mjs → list-BbfYuR8B.mjs} +1 -1
- package/dist/{list-AcjI7IXu.mjs → list-BiQ420kS.mjs} +1 -1
- package/dist/{list-BV-qhqJB.mjs → list-BjLjVNcZ.mjs} +1 -1
- package/dist/{list-pMhI_i46.mjs → list-BjP-K2tb.mjs} +2 -2
- package/dist/{list-Bkmb6qmP.mjs → list-BmhbG3wJ.mjs} +1 -1
- package/dist/{list-CUQa6nrb.mjs → list-BnoYDfr5.mjs} +1 -1
- package/dist/{list-DPNOIQbS.mjs → list-BskRDrtC.mjs} +1 -1
- package/dist/{list-BcTm5zD7.mjs → list-C2Jfy1Da.mjs} +1 -1
- package/dist/{list-DgEws5kk.mjs → list-C4N4ia-K.mjs} +1 -1
- package/dist/{list-Bh0hf0aa.mjs → list-CELONJ3c.mjs} +1 -1
- package/dist/{list-CSK4Ee6N.mjs → list-CQZwD2p8.mjs} +1 -1
- package/dist/{list-ClMrjYPe.mjs → list-Cd8kmSoR.mjs} +1 -1
- package/dist/{list-D2I4stFV.mjs → list-Ch6m2lp2.mjs} +3 -3
- package/dist/{list-DyKjezNg.mjs → list-Dt5fK66s.mjs} +1 -1
- package/dist/{list-Bt2qs02U.mjs → list-Du5brDb-.mjs} +1 -1
- package/dist/{list-D7iymMGH.mjs → list-E_agT4ZM.mjs} +1 -1
- package/dist/{list-DK0LD_us.mjs → list-KlezfVK2.mjs} +1 -1
- package/dist/{list-C0bBB4ay.mjs → list-_VIvph66.mjs} +1 -1
- package/dist/{list-9tV8el7U.mjs → list-qLFwCjmm.mjs} +3 -3
- package/dist/{login-DGfZBNuL.mjs → login-29tLLVJP.mjs} +3 -3
- package/dist/{logout-bG_ZJkyr.mjs → logout-DwmXJLsp.mjs} +1 -1
- package/dist/{measure-Do19ivCX.mjs → measure-DcHw_MiT.mjs} +5 -5
- package/dist/{nano-id-D_xVCG80.mjs → nano-id-BRmKx_yj.mjs} +1 -1
- package/dist/{parameter-values-gcfN0NVF.mjs → parameter-values-ZwmQ1Udg.mjs} +1 -1
- package/dist/{path-bfe3wQV4.mjs → path-BlDwkDf9.mjs} +2 -2
- package/dist/{poll-DsKAeWSG.mjs → poll-kX01Xu7c.mjs} +1 -1
- package/dist/{publish-uDuRQoQ5.mjs → publish-BEBIyLN5.mjs} +1 -1
- package/dist/{query-BBblM0de.mjs → query-BP-djKNO.mjs} +3 -3
- package/dist/{query-yzdVy8IY.mjs → query-BoU_Hk1V.mjs} +1 -1
- package/dist/{registry-flag-C6CMpxSu.mjs → registry-flag-DcJSw5a5.mjs} +1 -1
- package/dist/{remapping-BYNOF4xJ.mjs → remapping-5M8OXoYq.mjs} +1 -1
- package/dist/{remove-collection-C_nLjEG6.mjs → remove-collection-BKYePbf6.mjs} +1 -1
- package/dist/{render-DPahQNYA.mjs → render-CTBZejXY.mjs} +1 -1
- package/dist/{replace-Dx_IgvBM.mjs → replace-CRO_HjDu.mjs} +2 -2
- package/dist/{requirement-check-juL6K2it.mjs → requirement-check-BuzAsCEY.mjs} +1 -1
- package/dist/{rescan-values-C1ryy_S5.mjs → rescan-values-CuNJ1lGi.mjs} +3 -3
- package/dist/{rescan-values-B_5r6t7K.mjs → rescan-values-DMfiAgMb.mjs} +1 -1
- package/dist/{run-B19FOhID.mjs → run-C-3POoeR.mjs} +2 -2
- package/dist/{run-DM99qbxN.mjs → run-CizS77_E.mjs} +1 -1
- package/dist/{run-By9Q7-P6.mjs → run-DG2s6HbZ.mjs} +2 -2
- package/dist/{run-Dh4TQtVl.mjs → run-DVv5LbTr.mjs} +1 -1
- package/dist/{runs-BlnHJEpy.mjs → runs-Cga1onM9.mjs} +1 -1
- package/dist/{runtime-DMb47Kan.mjs → runtime-icvfPElD.mjs} +65 -21
- package/dist/{scaffold-xys21-_c.mjs → scaffold-rI9rqE8J.mjs} +4 -4
- package/dist/{schema-CItr2vjk.mjs → schema-ChNwnR_v.mjs} +1 -1
- package/dist/{schema-tables-CxgXdUtj.mjs → schema-tables-BsQB8kdp.mjs} +1 -1
- package/dist/{schemas-BLhPyQRt.mjs → schemas-DizhjGRh.mjs} +1 -1
- package/dist/{sdk-version-C_rurdw5.mjs → sdk-version-CW1yxLZG.mjs} +3 -3
- package/dist/{search-D9RL_Ao0.mjs → search-CO-lBs1n.mjs} +1 -1
- package/dist/{search-DW9byR1X.mjs → search-CZvjLzlk.mjs} +1 -1
- package/dist/{segment-DYN7sJO_.mjs → segment-CEkRgEM5.mjs} +5 -5
- package/dist/{send-OMqLoun6.mjs → send-DnACnI3O.mjs} +1 -1
- package/dist/{set-DjYrobzO.mjs → set-_14cgP8Q.mjs} +1 -1
- package/dist/{set-active-RCOa06in.mjs → set-active-uPlvtNW_.mjs} +1 -1
- package/dist/{set-data-actions-CcZHF3ot.mjs → set-data-actions-CUDz-Z1n.mjs} +3 -3
- package/dist/{set-enabled-IrDIT7Uc.mjs → set-enabled-BIaLKzh-.mjs} +1 -1
- package/dist/{set-sensitivity-ZJb78vYE.mjs → set-sensitivity-BiiFrr8R.mjs} +1 -1
- package/dist/{setting-DjFeW_Bd.mjs → setting-Exfniunx.mjs} +3 -3
- package/dist/{setup-71MuR246.mjs → setup-CHW9VP4d.mjs} +1 -1
- package/dist/{skills-yg-WfvpW.mjs → skills-CbMRgDyg.mjs} +1 -1
- package/dist/{skills-6NMamShR.mjs → skills-JvfWVDdS.mjs} +3 -3
- package/dist/{snippet-CnTWEAgc.mjs → snippet-OVXR6Y3M.mjs} +5 -5
- package/dist/{stash-CREL1rEx.mjs → stash-DuuL-oE4.mjs} +2 -2
- package/dist/{status-C7_WDust.mjs → status-CklSnHEH.mjs} +1 -1
- package/dist/{status-CIK0pGS1.mjs → status-kNuvMf-E.mjs} +2 -2
- package/dist/{subscription-Cssyopsy.mjs → subscription-CA2ij8ax.mjs} +5 -5
- package/dist/{subscriptions-DW-rgYA2.mjs → subscriptions-BVpir88T.mjs} +2 -2
- package/dist/{summary-BgYasLRg.mjs → summary-D4IdS4ui.mjs} +1 -1
- package/dist/{sync-schema-CERYSKAq.mjs → sync-schema-CmouoUmN.mjs} +4 -4
- package/dist/{sync-schema-Bw5lh64d.mjs → sync-schema-DGRksKzn.mjs} +1 -1
- package/dist/table-SnjFwjwZ.mjs +26 -0
- package/dist/{timeline-C1EGYIWm.mjs → timeline-BzZLfQ4C.mjs} +7 -7
- package/dist/{timeline-event-CNResXsb.mjs → timeline-event-Dl5VLbkp.mjs} +5 -5
- package/dist/transform-DVHety41.mjs +28 -0
- package/dist/transform-job-CTBdu_fH.mjs +22 -0
- package/dist/{transform-tag-Co2WuSBJ.mjs → transform-tag-Yp69-53i.mjs} +4 -4
- package/dist/{transform-test-DJTET6yX.mjs → transform-test-DOg55TiR.mjs} +6 -6
- package/dist/{transforms-D4WJPdxv.mjs → transforms-mIukRzGi.mjs} +1 -1
- package/dist/{transport-C23PjC9C.mjs → transport-CooEZWSM.mjs} +4 -3
- package/dist/{tree-BOzjsQT9.mjs → tree-CrI6CExE.mjs} +1 -1
- package/dist/{unpublish-jVyBAFYQ.mjs → unpublish-9xelQnKg.mjs} +1 -1
- package/dist/{unreferenced-CxZBGK-v.mjs → unreferenced-DwybWbv_.mjs} +1 -1
- package/dist/{update-DS7FwMdV.mjs → update-B2KG-bPS.mjs} +1 -1
- package/dist/{update-B0fK8ufL.mjs → update-B5o9YGR4.mjs} +1 -1
- package/dist/{update-DmVDc-cc.mjs → update-BGO8A-Dc.mjs} +1 -1
- package/dist/{update-CnOJU0E9.mjs → update-BMGh9Yut.mjs} +2 -2
- package/dist/{update-DkzE2qOr.mjs → update-BT-KU5ik.mjs} +1 -1
- package/dist/{update-DhyyfH1b.mjs → update-CRV8iYYM.mjs} +1 -1
- package/dist/{update-Datagi0N.mjs → update-CTReVn24.mjs} +1 -1
- package/dist/{update-C86ovTcd.mjs → update-CYo8FgXL.mjs} +1 -1
- package/dist/{update-DTkJqBmp.mjs → update-Cctb5Q6Q.mjs} +1 -1
- package/dist/{update-B2zy3jnR.mjs → update-Cdi5mRB0.mjs} +1 -1
- package/dist/{update-B9xWx1RV.mjs → update-CfH57l5u.mjs} +1 -1
- package/dist/{update-BvbuAD8_2.mjs → update-DJaxlhTr2.mjs} +1 -1
- package/dist/{update-Dmfimhno.mjs → update-DdoWropW.mjs} +1 -1
- package/dist/{update-B82aqBJ5.mjs → update-DeSEWxcE.mjs} +1 -1
- package/dist/{update-BPSI4D36.mjs → update-DlpaYaQJ.mjs} +1 -1
- package/dist/{update-nzPxtrWU.mjs → update-Dmc9beTx.mjs} +1 -1
- package/dist/{update-DTwwlTus.mjs → update-DsQWw0lg.mjs} +1 -1
- package/dist/{update-BP4Jzan1.mjs → update-_oK-yApr.mjs} +1 -1
- package/dist/{update-dashcard-dhjE7CQz.mjs → update-dashcard-2MHNS7N0.mjs} +1 -1
- package/dist/{update-SQtRtpRg.mjs → update-eXuJTw_J.mjs} +1 -1
- package/dist/{upgrade-Ckdl0SYl.mjs → upgrade-DqzD-StO.mjs} +2 -2
- package/dist/{upload-UYuGBsus.mjs → upload-BjannDFx.mjs} +2 -2
- package/dist/{upload-CTj7eVZk.mjs → upload-CPElN9Tz.mjs} +1 -1
- package/dist/{upload-DGl7iSh3.mjs → upload-CpVpqOx2.mjs} +3 -3
- package/dist/{uuid-CPLh7mDU.mjs → uuid-YUh1CUuc.mjs} +1 -1
- package/dist/{values-Bplkmfue.mjs → values-DE9CTWJ0.mjs} +1 -1
- package/dist/{verify-Cg1TFaPs.mjs → verify--wo2Ac1M.mjs} +2 -2
- package/dist/{verify-pLZ7b7JP.mjs → verify-DmJVskU0.mjs} +1 -1
- package/dist/{verify-CzlfG_Or.mjs → verify-qPqmekfD.mjs} +1 -1
- package/dist/{wait-D9yIDRpl.mjs → wait-COrnYsYy.mjs} +3 -3
- package/dist/{wait-flags-C4CH6rTJ.mjs → wait-flags-DIeSd2rv.mjs} +1 -1
- package/package.json +1 -1
- package/skill-data/data-app/SKILL.md +25 -23
- package/skill-data/data-app/template/README.md +8 -1
- package/skill-data/data-app/template/e2e/app.spec.ts +6 -0
- package/skill-data/data-app/template/gitignore +3 -0
- package/skill-data/data-app/template/package.json +12 -2
- package/skill-data/data-app/template/playwright.config.ts +14 -0
- package/skill-data/data-app/template/src/App.test.tsx +10 -0
- package/skill-data/data-app/template/src/metabase.actions.ts +0 -2
- package/skill-data/data-app/template/src/metabase.queries.ts +0 -2
- package/skill-data/data-app/template/src/test/render.tsx +10 -0
- package/skill-data/data-app/template/src/test/setup.ts +5 -0
- package/skill-data/data-app/template/tsconfig.json +2 -2
- package/skill-data/data-app/template/vitest.config.ts +9 -0
- package/skill-data/data-app-actions/SKILL.md +7 -5
- package/skill-data/data-app-data/SKILL.md +9 -11
- package/skill-data/data-app-filters/SKILL.md +6 -4
- package/skill-data/data-app-testing/SKILL.md +118 -0
- package/skill-data/data-app-ui/SKILL.md +1 -1
- package/dist/git-sync-BY0dqrLE.mjs +0 -29
- package/dist/table-Be5Vl7JT.mjs +0 -26
- package/dist/transform-Cev-LAhH.mjs +0 -28
- package/dist/transform-job-BnI6Ivqh.mjs +0 -22
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-app
|
|
3
|
-
description: Create, preview, release and manage a Metabase data app — a React app Metabase serves at /apps/<slug> from the synced git repository — scaffold it in the repository, run the dev preview and read its diagnostics feed, generate its questions and actions, build, push and import it, turn it off, move it to another instance, delete it. Triggers — "build a data app", "make an internal tool in Metabase", "scaffold a data app", "publish my data app", "update the app", "the app is blank". Start here; the UI is in `data-app-ui`, questions and charts in `data-app-data`, filter controls in `data-app-filters`, writes in `data-app-actions`.
|
|
3
|
+
description: Create, preview, release and manage a Metabase data app — a React app Metabase serves at /apps/<slug> from the synced git repository — scaffold it in the repository, run the dev preview and read its diagnostics feed, generate its questions and actions, build, push and import it, turn it off, move it to another instance, delete it. Triggers — "build a data app", "make an internal tool in Metabase", "scaffold a data app", "publish my data app", "update the app", "the app is blank". Start here; the UI is in `data-app-ui`, questions and charts in `data-app-data`, filter controls in `data-app-filters`, writes in `data-app-actions`, tests in `data-app-testing`.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
requires: [dataApps]
|
|
6
6
|
---
|
|
@@ -13,8 +13,8 @@ The work, in order:
|
|
|
13
13
|
|
|
14
14
|
1. Scaffold the app in the synced repository and install the SDK.
|
|
15
15
|
2. Give it data: fetch `src/metabase.schema.ts`, then define questions over the Library's published tables and metrics (`data-app-data`); writes are `data-app-actions`.
|
|
16
|
-
3. Start the dev preview (_Dev preview_), then write the UI under `src/` (`data-app-ui`; filter controls in `data-app-filters`).
|
|
17
|
-
4.
|
|
16
|
+
3. Start the dev preview (_Dev preview_), then write the UI under `src/` (`data-app-ui`; filter controls in `data-app-filters`), with a test next to each component (`data-app-testing`).
|
|
17
|
+
4. Pass the tests, then generate the collection, build, push and import (_Release_).
|
|
18
18
|
|
|
19
19
|
For every later change: first pass the checks in _An existing project_ (_Scaffold and install_), then change the source, then release (_Release_). The live app changes only through the import.
|
|
20
20
|
|
|
@@ -54,7 +54,7 @@ cd data_apps/sales-overview &&
|
|
|
54
54
|
|
|
55
55
|
`mb data-app sdk-version` reads the instance's version and, from the registry `npm install` uses, answers the SDK tag published for that Metabase major: its stable tag, or while it has none, its beta, then its alpha. Installing the tag writes the version it points at into `package.json` (`^0.65.1`), in place of the template's `*` or any version an existing project named. Run the block as one command: it stops at the first failure, so a refused tag installs nothing, where a plain `npm install` would install `latest` for the template's `*`. Never install a tag you picked yourself. When `package.json` already points the SDK at a local build (`file:` or `link:`), run only `npm install && npm run typecheck`. `sdk-version` fails on a development build (`vUNKNOWN`, `vLOCAL_DEV`, a `-SNAPSHOT` tag), which no published SDK matches: ask the user which SDK build to install. On any other failure, stop and tell the user what it says. The starter renders "Hello, data app".
|
|
56
56
|
|
|
57
|
-
The template is the bundle contract. Don't edit `package.json` by hand, and never rewrite `vite.config.ts`, `tsconfig.json` or `src/index.tsx`: `vite.config.ts` stays `export default dataAppConfig()` (its only option is `port`), and `src/index.tsx` default-exports the `DataAppFactory` — change it only to add a `providerProps` key. Metabase and the dev preview each wrap the app in a `<MetabaseProvider>`, so the app never renders one.
|
|
57
|
+
The template is the bundle contract. Don't edit `package.json` by hand, and never rewrite `vite.config.ts`, `vitest.config.ts`, `playwright.config.ts`, `tsconfig.json` or `src/index.tsx`: `vite.config.ts` stays `export default dataAppConfig()` (its only option is `port`), and `src/index.tsx` default-exports the `DataAppFactory` — change it only to add a `providerProps` key. Metabase and the dev preview each wrap the app in a `<MetabaseProvider>`, so the app never renders one.
|
|
58
58
|
|
|
59
59
|
**An existing project.** Before changing an app you didn't scaffold in this session, pass four checks:
|
|
60
60
|
|
|
@@ -116,12 +116,13 @@ curl -s "http://localhost:5174/__data-app/diagnostics?startEventId=0"
|
|
|
116
116
|
- The feed answers for the running bundle: entries from replaced builds are counted in `staleEntries`, and anything still broken reports again under the new `buildId` (`?includeStale=true` shows the withheld ones). A failed build doesn't advance `buildId` and doesn't reach the feed — read the `npm run dev` terminal.
|
|
117
117
|
- Quote `summary` as it is when you report it, and follow `hint` when there is one — except that you never add the Metabase URL to `allowed_hosts`. An origin goes in `allowed_hosts` in `data_app.yaml`, then restart `npm run dev`. A `frame-src` or `form-action` block can't be lifted in the preview (`data-app-ui`). The feed keeps the last 200 entries; `curl -X DELETE …/__data-app/diagnostics` clears it.
|
|
118
118
|
|
|
119
|
-
| `kind`
|
|
120
|
-
|
|
|
121
|
-
| `blocked-network`, `csp-violation`
|
|
122
|
-
| `blocked-api`
|
|
123
|
-
| `sdk-call` with `alert: true`
|
|
124
|
-
| `
|
|
119
|
+
| `kind` | Fix |
|
|
120
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| `blocked-network`, `csp-violation` | An external API: `data-app-ui`, _External APIs_. A `script-src` or `style-src` violation: bundle the asset instead. |
|
|
122
|
+
| `blocked-api` | Blocked in Metabase too: use the replacement in `data-app-ui`. |
|
|
123
|
+
| `sdk-call` with `alert: true` | A Metabase request failed; `summary` names it. |
|
|
124
|
+
| `sdk-call` for `/api/analytics-proxy` | Metabase's own usage analytics, not the app's: ignore it. |
|
|
125
|
+
| `error` | A bug; `detail` has the stack. |
|
|
125
126
|
|
|
126
127
|
## Release
|
|
127
128
|
|
|
@@ -129,8 +130,8 @@ Build the bundle last, test it in the dev preview, then push it with the source
|
|
|
129
130
|
|
|
130
131
|
1. On a read-write instance, `mb git-sync is-dirty --profile <name> --json`: when it reports unexported changes (a table just published to the Library, say), export them first (`git-sync`, its branch guard included), or the import refuses; then `git pull --ff-only` in `<repo>`.
|
|
131
132
|
2. In `<repo>`, `mb data-app generate-queries <slug> --profile <name>` and `mb data-app generate-actions <slug> --profile <name>`. They load the exports of `src/metabase.queries.ts` and of `src/metabase.actions.ts` with the app's Vite, so `npm install` runs in the app first, and each replaces its kind of file in `collections/data_apps/data_app__<slug>/`: one YAML file per question or action, named after its export in lowercase and carrying its `entityId`. A generated question shows as a table in Metabase whatever the app makes of it. Nothing changes in Metabase.
|
|
132
|
-
3. In the app, `npm run typecheck && npm run build`, which writes `dist/index.js`.
|
|
133
|
-
4. With `npm run dev` running
|
|
133
|
+
3. In the app, pass the tests (`data-app-testing`, _Before handoff_), then `npm run typecheck && npm run build`, which writes `dist/index.js`.
|
|
134
|
+
4. With `npm run dev` running, run `npm run test:e2e` (`data-app-testing`), which reuses that preview, then read the diagnostics feed (_Dev preview_): the run mounted every page, and the feed keeps what they reported after its tabs close. Fix what it reports, then generate and build again.
|
|
134
135
|
5. Commit `data_apps/<slug>/` — the source, `package.json`, `package-lock.json`, `data_app.yaml` and `dist/index.js` — and `collections/data_apps/` together, and push.
|
|
135
136
|
6. `mb git-sync import --profile <name>`, whatever a cached `has-remote-changes` says. The bundle, questions and actions are live at once.
|
|
136
137
|
|
|
@@ -142,17 +143,18 @@ A viewer needs one of their groups assigned to the app (otherwise "You don't hav
|
|
|
142
143
|
|
|
143
144
|
## Pitfalls
|
|
144
145
|
|
|
145
|
-
| Symptom
|
|
146
|
-
|
|
|
147
|
-
| The app still runs the old bundle
|
|
148
|
-
| Works in the preview, a question or action fails in Metabase
|
|
149
|
-
| Blank app, `Bundle did not assign a function to __dataAppFactory__`
|
|
150
|
-
| "Failed to fetch the user, the session might be invalid."
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
|
|
|
146
|
+
| Symptom | Fix |
|
|
147
|
+
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
148
|
+
| The app still runs the old bundle | `dist/index.js` isn't in the pushed commit, or the push wasn't imported: build, commit, push, import. |
|
|
149
|
+
| Works in the preview, a question or action fails in Metabase | `generate-queries` or `generate-actions` didn't run after the last change, or the files weren't committed with the bundle: _Release_. |
|
|
150
|
+
| Blank app, `Bundle did not assign a function to __dataAppFactory__` | `src/index.tsx` must `export default` the factory and nothing else; otherwise the diagnostics feed has the real error. |
|
|
151
|
+
| "Failed to fetch the user, the session might be invalid." | A bad key in `<repo>/.env.local`, or CORS (_Dev preview_). |
|
|
152
|
+
| The app stays on loading; the terminal says "Failed to load Embedding SDK bundle" | No `<repo>/.env.local`, or a wrong `DATA_APP_MB_URL` in it (_Dev preview_). |
|
|
153
|
+
| A bundle of several MB | `vite.config.ts` doesn't use `dataAppConfig()`, or the SDK isn't the tag `mb data-app sdk-version` answers. |
|
|
154
|
+
| "Invalid hook call" | A second React got bundled: nothing may add another `react` or `react-dom`. |
|
|
155
|
+
| Drill-through popups don't open | The app renders its own `<MetabaseProvider>`: remove it. |
|
|
156
|
+
| An upgraded SDK still behaves like the old one | Vite caches it: stop `npm run dev`, delete `node_modules/.vite`, start again. |
|
|
157
|
+
| A viewer's query or action fails with 403 | It reads a table not published to the Library on that instance, or the viewer lacks data access to its tables. |
|
|
156
158
|
|
|
157
159
|
## Change, move, delete
|
|
158
160
|
|
|
@@ -25,7 +25,9 @@ In the app:
|
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
npm run dev # preview at http://localhost:5174, in the sandbox Metabase runs apps in
|
|
28
|
-
npm run typecheck # type-checks src/ and
|
|
28
|
+
npm run typecheck # type-checks src/ and the configs
|
|
29
|
+
npm run test:unit # runs the unit tests next to the components
|
|
30
|
+
npm run test:e2e # runs the Playwright specs in e2e/ against the preview
|
|
29
31
|
npm run build # builds dist/index.js, the app's bundle
|
|
30
32
|
```
|
|
31
33
|
|
|
@@ -44,3 +46,8 @@ included, with the files `generate-queries` and `generate-actions` write under
|
|
|
44
46
|
|
|
45
47
|
`npm run dev` reads `DATA_APP_MB_URL` and `DATA_APP_MB_API_KEY` from
|
|
46
48
|
`.env.local` at the repository root; `.env.local.example` lists them.
|
|
49
|
+
|
|
50
|
+
`npm run test:e2e` starts the preview, or reuses one already running; the first
|
|
51
|
+
run on a machine needs `npx playwright install chromium`. In CI, set
|
|
52
|
+
`DATA_APP_MB_URL` and `DATA_APP_MB_API_KEY` in the job's environment, against the
|
|
53
|
+
instance `src/metabase.schema.ts` was generated from.
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "vite",
|
|
8
8
|
"build": "vite build --outDir dist",
|
|
9
|
-
"typecheck": "tsc --noEmit"
|
|
9
|
+
"typecheck": "tsc --noEmit",
|
|
10
|
+
"test:unit": "vitest run",
|
|
11
|
+
"test:e2e": "playwright test"
|
|
10
12
|
},
|
|
11
13
|
"dependencies": {
|
|
12
14
|
"@metabase/embedding-sdk-react": "*",
|
|
@@ -14,12 +16,20 @@
|
|
|
14
16
|
"react-dom": "^19.0.0"
|
|
15
17
|
},
|
|
16
18
|
"devDependencies": {
|
|
19
|
+
"@playwright/test": "^1.64.1",
|
|
20
|
+
"@testing-library/dom": "^10.4.2",
|
|
21
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
22
|
+
"@testing-library/react": "^16.3.3",
|
|
23
|
+
"@testing-library/user-event": "^14.6.8",
|
|
24
|
+
"@types/node": "^24.0.0",
|
|
17
25
|
"@types/react": "^19.0.0",
|
|
18
26
|
"@types/react-dom": "^19.0.0",
|
|
19
27
|
"@vitejs/plugin-react": "^6.0.2",
|
|
28
|
+
"jsdom": "^30.1.3",
|
|
20
29
|
"typescript": "^6.0.3",
|
|
21
30
|
"vite": "^8.0.16",
|
|
22
31
|
"vite-plugin-css-injected-by-js": "^3.5.2",
|
|
23
|
-
"vite-plugin-svgr": "^5.2.0"
|
|
32
|
+
"vite-plugin-svgr": "^5.2.0",
|
|
33
|
+
"vitest": "^5.0.5"
|
|
24
34
|
}
|
|
25
35
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
const BASE_URL = process.env.PLAYWRIGHT_BASE_URL ?? "http://localhost:5174/";
|
|
4
|
+
const PORT = Number(new URL(BASE_URL).port);
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
testDir: "e2e",
|
|
8
|
+
use: { ...devices["Desktop Chrome"], baseURL: BASE_URL },
|
|
9
|
+
webServer: {
|
|
10
|
+
command: `npm run dev -- --port ${PORT} --strictPort`,
|
|
11
|
+
port: PORT,
|
|
12
|
+
reuseExistingServer: true,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { screen } from "@testing-library/react";
|
|
2
|
+
import { expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import App from "./App";
|
|
5
|
+
import { renderWithProviders } from "./test/render";
|
|
6
|
+
|
|
7
|
+
it("renders the starter page", () => {
|
|
8
|
+
renderWithProviders(<App />);
|
|
9
|
+
expect(screen.getByRole("heading", { name: "Hello, data app" })).toBeInTheDocument();
|
|
10
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MetabaseTestProvider,
|
|
3
|
+
type MetabaseTestProviderProps,
|
|
4
|
+
} from "@metabase/embedding-sdk-react/testing";
|
|
5
|
+
import { render } from "@testing-library/react";
|
|
6
|
+
import type { ReactElement } from "react";
|
|
7
|
+
|
|
8
|
+
export function renderWithProviders(ui: ReactElement, options: MetabaseTestProviderProps = {}) {
|
|
9
|
+
return render(<MetabaseTestProvider {...options}>{ui}</MetabaseTestProvider>);
|
|
10
|
+
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"noUnusedLocals": false,
|
|
20
20
|
"noUnusedParameters": false,
|
|
21
21
|
"noFallthroughCasesInSwitch": true,
|
|
22
|
-
"types": ["vite/client"]
|
|
22
|
+
"types": ["vite/client", "node"]
|
|
23
23
|
},
|
|
24
|
-
"include": ["src", "vite.config.ts"]
|
|
24
|
+
"include": ["src", "e2e", "vite.config.ts", "vitest.config.ts", "playwright.config.ts"]
|
|
25
25
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-app-actions
|
|
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`.
|
|
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`; tests are `data-app-testing`.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
requires: [dataApps]
|
|
6
6
|
---
|
|
@@ -12,16 +12,16 @@ A data app writes through **table actions**: an insert, update or delete of one
|
|
|
12
12
|
```ts
|
|
13
13
|
import { defineAction } from "@metabase/embedding-sdk-react/data-app";
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { orders } from "./metabase.schema";
|
|
16
16
|
|
|
17
17
|
export const updateOrder = defineAction({
|
|
18
18
|
entityId: "J2mXq8sLb0vT5nYcW4kRd",
|
|
19
19
|
kind: "row/update",
|
|
20
|
-
table:
|
|
20
|
+
table: orders,
|
|
21
21
|
});
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
- `kind` is `row/create`, `row/update` or `row/delete`; `table` is a table of `schema
|
|
24
|
+
- `kind` is `row/create`, `row/update` or `row/delete`; `table` is a table of `src/metabase.schema.ts`, imported by its name, or `schema.tables.<table>` when the file exports only `schema`. 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
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
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
27
|
- To drop an action, delete its export.
|
|
@@ -122,4 +122,6 @@ After a write succeeds, refetch every query on screen it could have changed: `aw
|
|
|
122
122
|
3. The screen doesn't update: see _Refresh_.
|
|
123
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_).
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
## Test
|
|
126
|
+
|
|
127
|
+
Every form and button that runs an action gets a unit test that mocks the action, drives the inputs, and checks the parameters it sends and the refresh that follows, plus one with `mockDataAppActionError` for the error shown as it comes (`data-app-testing`, _Actions_). The page's Playwright spec opens each form and checks its fields, and submits it only when the user has said the app's database may be written to (`data-app-testing`, _End-to-end tests_). Then release the app (`data-app`, _Release_).
|
|
@@ -32,7 +32,7 @@ When the app needs a table or metric the Library lacks, stop: name what's missin
|
|
|
32
32
|
cd <repo> && mb data-app generate-schema <slug> --profile <name>
|
|
33
33
|
```
|
|
34
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.
|
|
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. 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 table, metric or field. Never edit the file.
|
|
36
36
|
|
|
37
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
38
|
|
|
@@ -44,7 +44,7 @@ The file runs to thousands of lines. Every table, field, segment, measure and me
|
|
|
44
44
|
grep -n -B2 -E 'type: "(table|segment|measure|metric)"' src/metabase.schema.ts
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
Choose the definitions from this list: `schema
|
|
47
|
+
Choose the definitions from this list. A table or metric listed as `export const <name> = {` is its own export: import the ones the app uses by that name (`import { orders, revenue } from "./metabase.schema"`), and reach a table's segments and measures as `orders.segments.<key>` and `orders.measures.<key>`. The bundle then holds only what the app imports, while `schema`, which the file also exports, holds every table and metric: never import it. A file whose tables and metrics are listed without `export const` (`orders: {`) exports only `schema`: there, write `schema.tables.<table>` and `schema.metrics.<key>` wherever the examples below import a table or metric by name.
|
|
48
48
|
|
|
49
49
|
2. Read each table or metric the question uses from its line to the next line in the list: a table's fields, each with its metadata line, or a metric's dimensions.
|
|
50
50
|
|
|
@@ -60,9 +60,7 @@ import {
|
|
|
60
60
|
orderBy,
|
|
61
61
|
} from "@metabase/embedding-sdk-react/data-app";
|
|
62
62
|
|
|
63
|
-
import {
|
|
64
|
-
|
|
65
|
-
const orders = schema.tables.orders;
|
|
63
|
+
import { orders, reviews } from "./metabase.schema";
|
|
66
64
|
|
|
67
65
|
export const revenueByMonth = defineQuery({
|
|
68
66
|
entityId: "Vh3kq0wYc8TnS2aJm1LxR",
|
|
@@ -73,13 +71,13 @@ export const revenueByMonth = defineQuery({
|
|
|
73
71
|
|
|
74
72
|
export const latestReviews = defineQuery({
|
|
75
73
|
entityId: "pW9dE4uNq7Zb1fGhK3sTy",
|
|
76
|
-
source:
|
|
77
|
-
orderBys: [orderBy(
|
|
74
|
+
source: reviews,
|
|
75
|
+
orderBys: [orderBy(reviews.fields.createdAt, "desc")],
|
|
78
76
|
limit: 20,
|
|
79
77
|
});
|
|
80
78
|
```
|
|
81
79
|
|
|
82
|
-
- `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
|
|
80
|
+
- `source` is a table of `src/metabase.schema.ts`; `aggregations`, `breakouts`, `filters`, `orderBys`, `limit` and `fields` (the columns to keep) take its fields, its segments and measures, and the file's metrics as aggregations (`aggregations: [revenue]`). A field that isn't the table's, or an operator its type doesn't take, fails to compile.
|
|
83
81
|
- The export's name is the question's name in Metabase, as written (`customerList`).
|
|
84
82
|
- 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.
|
|
85
83
|
|
|
@@ -97,7 +95,7 @@ A result column's `name` keys the rows and names the column in runtime clauses:
|
|
|
97
95
|
|
|
98
96
|
- A column reached through a foreign key keeps its own name (`CATEGORY`, not `PRODUCTS__via__PRODUCT_ID__CATEGORY`).
|
|
99
97
|
- 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`.
|
|
100
|
-
- A `Date` column's values arrive as ISO strings
|
|
98
|
+
- A `Date` column's values arrive as ISO strings, though the row type is `string | Date`: format them through `new Date(value)`.
|
|
101
99
|
|
|
102
100
|
## Rows: `useMetabaseQuery`
|
|
103
101
|
|
|
@@ -159,7 +157,7 @@ return <StaticQuestion card={card} height={360} />;
|
|
|
159
157
|
|
|
160
158
|
## Runtime clauses
|
|
161
159
|
|
|
162
|
-
Both hooks take a second argument: one object with the clauses the UI changes, and `enabled`. They run on top of the question and name its columns:
|
|
160
|
+
Both hooks take a second argument: one object with the clauses the UI changes, and `enabled`. They run on top of the question and name its columns. Keep them in a `<Component>.query.ts` file next to the component, so its test mocks the same clauses (`data-app-testing`):
|
|
163
161
|
|
|
164
162
|
```tsx
|
|
165
163
|
import { aggregations, filter, orderBy } from "@metabase/embedding-sdk-react/data-app";
|
|
@@ -174,7 +172,7 @@ const { query } = useMetabaseQueryObject(orderRows, {
|
|
|
174
172
|
});
|
|
175
173
|
```
|
|
176
174
|
|
|
177
|
-
- A column is `{ type: "column", name }` with a result column's `name`, or a field
|
|
175
|
+
- A column is `{ type: "column", name }` with a result column's `name`, or a table's field (`orders.fields.total`); 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`).
|
|
178
176
|
|
|
179
177
|
| Column type | Operators |
|
|
180
178
|
| ----------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-app-filters
|
|
3
|
-
description: Build the filter controls of a Metabase data app — the filter contract, which cards a filter reaches, All by default, options from their own question, a searchable combobox for entities, date presets, `DateRangePopover` and `DateRangeCalendar` with labels from `useDateFormatter`, and a single-date picker. Triggers — "add a filter to the app", "filter the chart by date", "a date range picker", "filter by customer", "a dropdown of categories", "the filter doesn't change the chart", "the date shows the previous day". The query side — runtime clauses and their limits — is in `data-app-data`.
|
|
3
|
+
description: Build the filter controls of a Metabase data app — the filter contract, which cards a filter reaches, All by default, options from their own question, a searchable combobox for entities, date presets, `DateRangePopover` and `DateRangeCalendar` with labels from `useDateFormatter`, and a single-date picker. Triggers — "add a filter to the app", "filter the chart by date", "a date range picker", "filter by customer", "a dropdown of categories", "the filter doesn't change the chart", "the date shows the previous day". The query side — runtime clauses and their limits — is in `data-app-data`; tests are `data-app-testing`.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
|
|
5
5
|
requires: [dataApps]
|
|
6
6
|
---
|
|
@@ -21,7 +21,7 @@ Before any control, write one row per filter: the question that gives its option
|
|
|
21
21
|
- A filter in the page's global bar changes every panel that can take it. One that can't reach a panel is scoped to its section, visibly, or left out. A KPI and its detail table about the same thing take the same filters, unless the UI says why not.
|
|
22
22
|
- A KPI on an aggregated question shows one complete bucket (`data-app-data`, _Runtime clauses_): it gets its own control of one-bucket presets starting at the last complete bucket, never All time, rather than a shared bar's ranges.
|
|
23
23
|
- One date control per scope. Never a global date range beside a page-specific date where one of the two does nothing; a page whose cards use another date column gets one control for that column.
|
|
24
|
-
- Build each panel's clauses from its own question's columns,
|
|
24
|
+
- Build each panel's clauses from its own question's columns, as a function of the filter state in the panel's `<Component>.query.ts` (`data-app-data`, _Runtime clauses_). Never reuse clauses built for another question.
|
|
25
25
|
|
|
26
26
|
## Values and options
|
|
27
27
|
|
|
@@ -57,7 +57,7 @@ import { DateRangePopover, filter, useDateFormatter } from "@metabase/embedding-
|
|
|
57
57
|
const { formatDateRange } = useDateFormatter();
|
|
58
58
|
const [range, setRange] = useState<[string | null, string | null]>([null, null]);
|
|
59
59
|
const [start, end] = range;
|
|
60
|
-
//
|
|
60
|
+
// in the panel's .query.ts: filters: start && end ? [filter({ type: "column", name: "CREATED_AT" }, "between", [start, end])] : []
|
|
61
61
|
|
|
62
62
|
<DateRangePopover value={range} onChange={setRange}>
|
|
63
63
|
<button className="filter-button">{formatDateRange(range) || "Custom"}</button>
|
|
@@ -92,4 +92,6 @@ 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.
|
|
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.
|
|
96
|
+
|
|
97
|
+
Every filter gets a unit test: its options question mocked, and each panel it reaches mocked with that panel's clauses for All and for one picked value, checking the panel shows that value's rows after the pick (`data-app-testing`, _Runtime clauses_). The page's Playwright spec picks a value in each filter and checks that a panel it reaches changes (`data-app-testing`, _End-to-end tests_). Then release the app (`data-app`, _Release_).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-app-testing
|
|
3
|
+
description: Test a Metabase data app — a unit test next to each component with Vitest, Testing Library and the SDK's `MetabaseTestProvider`, its questions and actions mocked from the exports of `src/metabase.queries.ts` and `src/metabase.actions.ts`, and runtime clauses in a `<Component>.query.ts` file the component and its test share; a Playwright spec per page against the dev preview and real data. Triggers — "test the data app", "add tests", "mock a query", "the test fails with No mock for query", "add an e2e test", "run the Playwright tests". Creating and releasing the app is `data-app`; its hooks are `data-app-data` and `data-app-actions`.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash
|
|
5
|
+
requires: [dataApps]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Testing a data app
|
|
9
|
+
|
|
10
|
+
## Unit tests
|
|
11
|
+
|
|
12
|
+
Every component that renders data or runs an action gets a test next to it, `<Component>.test.tsx`. `npm run test:unit` runs them with Vitest, jsdom and Testing Library, with no Metabase instance: `renderWithProviders` in `src/test/render.tsx` wraps the component in `MetabaseTestProvider` from `@metabase/embedding-sdk-react/testing`, and the test passes the answer to every question and action the component runs. Add the app's own providers (theme, router) to `renderWithProviders`; leave the rest of the file as it is. The template's `src/App.test.tsx` checks the starter heading: rewrite it for the app's `App` once the starter page goes.
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { mockDataAppQuery } from "@metabase/embedding-sdk-react/testing";
|
|
16
|
+
import { screen } from "@testing-library/react";
|
|
17
|
+
import { expect, it } from "vitest";
|
|
18
|
+
|
|
19
|
+
import { ordersList } from "../metabase.queries";
|
|
20
|
+
import { renderWithProviders } from "../test/render";
|
|
21
|
+
|
|
22
|
+
import { OrdersTable } from "./OrdersTable";
|
|
23
|
+
|
|
24
|
+
it("shows orders", async () => {
|
|
25
|
+
renderWithProviders(<OrdersTable />, {
|
|
26
|
+
dataAppQueries: [mockDataAppQuery(ordersList, [{ ID: 1, STATUS: "paid" }])],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(await screen.findByText("paid")).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- Rows are typed from the question's export, and partial: give the columns the test asserts on. The mock answers with the query's columns, and the ones a row leaves out come back as `null`.
|
|
34
|
+
- Assert what the user sees, found by role or text, and wait for data with `findBy…`. Drive interactions with `@testing-library/user-event`.
|
|
35
|
+
- `mockDataAppQueryError` and `mockDataAppActionError` answer with an error, for the error state of a component that runs the query with `useMetabaseQuery` or the action with `useAction`. A query with runtime clauses takes them as the second argument, as `mockDataAppQuery` does: `mockDataAppQueryError(ordersList, ordersByStatus, { status: 500, message: "Query failed" })`.
|
|
36
|
+
- An SDK component such as `StaticQuestion` renders only its children unless the test passes one: `StaticQuestion: () => <p>Revenue chart</p>`. A panel it draws still needs its query mocked, since `useMetabaseQueryObject` resolves it (the rows don't matter); its query runs inside the component, so that panel's error state is the end-to-end tests' to check.
|
|
37
|
+
|
|
38
|
+
### Runtime clauses: `<Component>.query.ts`
|
|
39
|
+
|
|
40
|
+
A mock answers a query only when its runtime clauses equal what the component passes (`enabled` aside). So a component keeps its clauses in a `<Component>.query.ts` file next to it, and the component and its test import the same value:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// OrdersByStatus.query.ts
|
|
44
|
+
import { aggregations, filter } from "@metabase/embedding-sdk-react/data-app";
|
|
45
|
+
|
|
46
|
+
export const ordersByStatus = {
|
|
47
|
+
breakouts: [{ type: "column", name: "STATUS" }],
|
|
48
|
+
aggregations: [aggregations.count()],
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
export function ordersWithStatus(status: string) {
|
|
52
|
+
return { filters: [filter({ type: "column", name: "STATUS" }, "=", status)] } as const;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
// OrdersByStatus.tsx
|
|
58
|
+
const { data } = useMetabaseQuery(ordersList, ordersByStatus);
|
|
59
|
+
|
|
60
|
+
// OrdersByStatus.test.tsx
|
|
61
|
+
renderWithProviders(<OrdersByStatus />, {
|
|
62
|
+
dataAppQueries: [mockDataAppQuery(ordersList, ordersByStatus, [{ STATUS: "paid", count: 12 }])],
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Clauses built from state are a function of that state, as `ordersWithStatus` is: the test mocks the call for each value it selects. A request no mock matches fails with `No mock for query "<entityId>"`: the clauses differ from every mock, or the query has none.
|
|
67
|
+
|
|
68
|
+
### Actions
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { mockDataAppAction } from "@metabase/embedding-sdk-react/testing";
|
|
72
|
+
import userEvent from "@testing-library/user-event";
|
|
73
|
+
|
|
74
|
+
import { updateOrder } from "../metabase.actions";
|
|
75
|
+
|
|
76
|
+
const updateOrderMock = mockDataAppAction(updateOrder, { "rows-updated": 1 });
|
|
77
|
+
|
|
78
|
+
renderWithProviders(<OrderPage />, { dataAppActions: [updateOrderMock] });
|
|
79
|
+
|
|
80
|
+
await userEvent.click(screen.getByRole("button", { name: "Mark as refunded" }));
|
|
81
|
+
expect(updateOrderMock.lastCall()?.parameters).toEqual({ id: 1, status: "refunded" });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The response is what the action's kind answers (`data-app-actions`): `created-row` for an insert, `rows-updated` for an update, `rows-deleted` for a delete. `calls()` lists every call, `lastCall()` the latest. A parameter that isn't a column of the action's table, or whose value doesn't match the column's `jsType`, fails the call instead of reaching the mock.
|
|
85
|
+
|
|
86
|
+
## End-to-end tests
|
|
87
|
+
|
|
88
|
+
The specs in `e2e/` are Playwright tests against the dev preview (`data-app`, _Dev preview_) and the instance's real data: they check that the pieces fit — every page opens, its questions return rows, its actions exist — not that the numbers are right. `npm run test:e2e` starts the preview, or reuses one already running, so it needs `<repo>/.env.local` like `npm run dev`; the first run on a machine needs `npx playwright install chromium`.
|
|
89
|
+
|
|
90
|
+
Write one spec per page in `e2e/`. The template's `e2e/app.spec.ts` checks the starter heading: once the starter page goes, make it the first page's spec:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { expect, test } from "@playwright/test";
|
|
94
|
+
|
|
95
|
+
test("orders page shows warehouse data", async ({ page }) => {
|
|
96
|
+
await page.goto("orders");
|
|
97
|
+
await expect(page.getByRole("row")).not.toHaveCount(0);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("status filter updates orders table", async ({ page }) => {
|
|
101
|
+
await page.goto("orders");
|
|
102
|
+
await page.getByRole("combobox", { name: "Status" }).fill("refunded");
|
|
103
|
+
await page.getByRole("option", { name: "refunded" }).click();
|
|
104
|
+
await expect(page.getByRole("cell", { name: "paid" })).toHaveCount(0);
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- Assert data, not only headings: rows, values and chart contents are what a failed query takes away. Then each interaction — a filter, sorting, a link to another page — and the view it changes.
|
|
109
|
+
- Locate by role and accessible name (`getByRole`, `getByLabel`), as a user finds things. A name matches as a substring unless `exact: true` is passed: "Ship order 12" also finds "Ship order 120".
|
|
110
|
+
- Navigate with relative paths (`page.goto("orders")`, `page.goto("")` for the first page), never `/orders`.
|
|
111
|
+
- An action spec opens the action's form and checks its fields. Submit it only when the user has said the app's database may be written to: a submitted action changes real data.
|
|
112
|
+
- A failure whose cause isn't on the page is in the diagnostics feed (`data-app`, _Dev preview_).
|
|
113
|
+
|
|
114
|
+
The same specs run in CI, with `DATA_APP_MB_URL` and `DATA_APP_MB_API_KEY` set in the job's environment, against the instance `src/metabase.schema.ts` was generated from: the preview runs each question and action by that instance's numeric IDs. CI installs the SDK from `package.json`, so it needs a published version there: a `file:` path to a local build resolves only on the machine that has it.
|
|
115
|
+
|
|
116
|
+
## Before handoff
|
|
117
|
+
|
|
118
|
+
Run `npm run test:unit` and `npm run typecheck` after every round of edits, and `npm run test:e2e` once the pages render data; all three pass before the app is released (`data-app`, _Release_).
|
|
@@ -128,4 +128,4 @@ Metabase mirrors each route to `/apps/<slug>/<path>`, and a reload there opens t
|
|
|
128
128
|
|
|
129
129
|
## Before handoff
|
|
130
130
|
|
|
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%"`).
|
|
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%"`). Pass the tests (`data-app-testing`, _Before handoff_) with `npm run dev` running, read the diagnostics feed right after the e2e run, which mounts every panel, then release the app (`data-app`, _Release_).
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DxaqX3Gg.mjs";
|
|
2
|
-
//#region src/commands/git-sync/index.ts
|
|
3
|
-
var git_sync_default = defineCommandGroup({
|
|
4
|
-
name: "git-sync",
|
|
5
|
-
description: "Sync Metabase content with a git remote",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "git-sync",
|
|
8
|
-
purpose: "import/export round-trip and dirty checks"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
status: () => import("./status-C7_WDust.mjs").then((mod) => mod.default),
|
|
12
|
-
"is-dirty": () => import("./is-dirty-DgrWNWdj.mjs").then((mod) => mod.default),
|
|
13
|
-
"has-remote-changes": () => import("./has-remote-changes-CMMXEsXa.mjs").then((mod) => mod.default),
|
|
14
|
-
dirty: () => import("./dirty-DEsgt8QN.mjs").then((mod) => mod.default),
|
|
15
|
-
"current-task": () => import("./current-task-CYWaDg5P.mjs").then((mod) => mod.default),
|
|
16
|
-
"cancel-task": () => import("./cancel-task-0N0qb4_g.mjs").then((mod) => mod.default),
|
|
17
|
-
wait: () => import("./wait-D9yIDRpl.mjs").then((mod) => mod.default),
|
|
18
|
-
import: () => import("./import-DZmfmoBw.mjs").then((mod) => mod.default),
|
|
19
|
-
export: () => import("./export-CikXGxZP.mjs").then((mod) => mod.default),
|
|
20
|
-
"export-preflight": () => import("./export-preflight-2RkCrd6x.mjs").then((mod) => mod.default),
|
|
21
|
-
stash: () => import("./stash-CREL1rEx.mjs").then((mod) => mod.default),
|
|
22
|
-
branches: () => import("./branches-wa3G1T3B.mjs").then((mod) => mod.default),
|
|
23
|
-
"create-branch": () => import("./create-branch-CQHIvpmr.mjs").then((mod) => mod.default),
|
|
24
|
-
"add-collection": () => import("./add-collection-Bdnq6dfy.mjs").then((mod) => mod.default),
|
|
25
|
-
"remove-collection": () => import("./remove-collection-C_nLjEG6.mjs").then((mod) => mod.default)
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
//#endregion
|
|
29
|
-
export { git_sync_default as default };
|
package/dist/table-Be5Vl7JT.mjs
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DxaqX3Gg.mjs";
|
|
2
|
-
//#region src/commands/table/index.ts
|
|
3
|
-
var table_default = defineCommandGroup({
|
|
4
|
-
name: "table",
|
|
5
|
-
description: "Manage Metabase tables",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "metadata",
|
|
8
|
-
purpose: "table and column metadata, semantic types, visibility"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
list: () => import("./list-CcFPkvbL.mjs").then((m) => m.default),
|
|
12
|
-
get: () => import("./get-c5S1A1KR.mjs").then((m) => m.default),
|
|
13
|
-
fields: () => import("./fields-30XWd-y0.mjs").then((m) => m.default),
|
|
14
|
-
fks: () => import("./fks-DbCuuP96.mjs").then((m) => m.default),
|
|
15
|
-
update: () => import("./update-Dmfimhno.mjs").then((m) => m.default),
|
|
16
|
-
"sync-schema": () => import("./sync-schema-Bw5lh64d.mjs").then((m) => m.default),
|
|
17
|
-
"rescan-values": () => import("./rescan-values-B_5r6t7K.mjs").then((m) => m.default),
|
|
18
|
-
"discard-values": () => import("./discard-values-CkGnpZB3.mjs").then((m) => m.default),
|
|
19
|
-
"bulk-edit": () => import("./bulk-edit-BPFITnRN.mjs").then((m) => m.default),
|
|
20
|
-
"bulk-sync-schema": () => import("./bulk-sync-schema-C_HNWZpZ.mjs").then((m) => m.default),
|
|
21
|
-
"bulk-rescan-values": () => import("./bulk-rescan-values-DaeLpv7G.mjs").then((m) => m.default),
|
|
22
|
-
"bulk-discard-values": () => import("./bulk-discard-values-BHryu-rZ.mjs").then((m) => m.default)
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
//#endregion
|
|
26
|
-
export { table_default as default };
|