@metabase/cli 0.3.1-alpha.versioning.9ac5f50 → 0.3.2-alpha.fix-transform-test-ee-path.041c793
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-Dmd-uNeU.mjs → add-collection-73X1DmCM.mjs} +5 -5
- package/dist/{alert-D1u2MVZj.mjs → alert-BB38lWSL.mjs} +7 -7
- package/dist/{alerts-DcBjcfEE.mjs → alerts-DxyzqLSU.mjs} +6 -6
- package/dist/{append-B9Htvmab.mjs → append-CHme1Enm.mjs} +4 -4
- package/dist/{archive-BUoYMkxO.mjs → archive-BGiDxu8O.mjs} +3 -3
- package/dist/{archive-Bf014rFm.mjs → archive-BMyvyf62.mjs} +3 -3
- package/dist/{archive-BmsZFOZY.mjs → archive-C4Y2B58q.mjs} +3 -3
- package/dist/{archive-BNivAYGr.mjs → archive-CP5Hlqjw.mjs} +4 -4
- package/dist/{archive-CvU2z5192.mjs → archive-Cq3fnc0v2.mjs} +5 -5
- package/dist/{archive-B660RguB.mjs → archive-CqKqNdUh.mjs} +5 -5
- package/dist/{archive-CgmidYZV.mjs → archive-Czo5T0Lp.mjs} +3 -3
- package/dist/{archive-BVmFGFwG.mjs → archive-DBcxZwLd.mjs} +5 -5
- package/dist/{archive-DhDQIKR_.mjs → archive-DKFPJ9j3.mjs} +5 -5
- package/dist/{archive-CNif6BKy.mjs → archive-DPL1qOuL.mjs} +5 -5
- package/dist/{archive-bPdDITuY.mjs → archive-eS-XA74p.mjs} +3 -3
- package/dist/{auth-CefYEPP5.mjs → auth-6YyB0HNB.mjs} +5 -5
- package/dist/{body-C7m9q4cm.mjs → body-OjAWKVaU.mjs} +3 -3
- package/dist/{branches-pz04OjF2.mjs → branches-D5YLVFDK.mjs} +3 -3
- package/dist/{cancel-CNLnv19e.mjs → cancel-DeRIq1YJ.mjs} +3 -3
- package/dist/{cancel-task-DbnxSh7U.mjs → cancel-task-CqExODVm.mjs} +4 -4
- package/dist/card-BMSqofd7.mjs +24 -0
- package/dist/{card-zyUkr2nS.mjs → card-CEkp1mcI.mjs} +1 -1
- package/dist/{card-DZxRmver.mjs → card-voh1k4hl.mjs} +14 -11
- package/dist/{cards-DtYlVoGP.mjs → cards-B813G9I5.mjs} +6 -6
- package/dist/cli.mjs +223 -211
- package/dist/{client-Bv7Iwdvh.mjs → client-cJ7aw0Gt.mjs} +1788 -72
- package/dist/collection-BfNg7tEg.mjs +20 -0
- package/dist/{collection-WFdBeyqa.mjs → collection-BxdPxD38.mjs} +1 -1
- package/dist/{collection-DALwHnbz.mjs → collection-DYM0p3Xl.mjs} +1 -1
- package/dist/{collection-namespace-CvT0TIZA.mjs → collection-namespace-CVzDgJV0.mjs} +2 -2
- package/dist/{content-translation-D7POzJJ6.mjs → content-translation-QKWt9l76.mjs} +3 -3
- package/dist/{create-JOXq0ULN.mjs → create-4UnoQvsy.mjs} +4 -4
- package/dist/{create-CLgalJUe.mjs → create-BJad6MR82.mjs} +7 -7
- package/dist/{create-Bh2j733n.mjs → create-BLiB2xqo.mjs} +6 -6
- package/dist/{create-DGHILnnk.mjs → create-BWp6L_dW.mjs} +4 -4
- package/dist/{create-Di4YvIbK.mjs → create-Bef5eBCA.mjs} +4 -4
- package/dist/{create-CGgPnb7L.mjs → create-CMV3qlzJ.mjs} +3 -3
- package/dist/{create-Ds-DnSBe.mjs → create-CWGsiFvU.mjs} +3 -3
- package/dist/{create-DhDREiiy.mjs → create-CoFg1p6m.mjs} +3 -3
- package/dist/{create-CGPle4nE.mjs → create-CvIeb1NU.mjs} +6 -6
- package/dist/{create-Bwg-5p08.mjs → create-CvpeAcFc.mjs} +3 -3
- package/dist/{create-DYd_o9BD.mjs → create-D50TxVTk.mjs} +4 -4
- package/dist/{create-DnqnjGGf.mjs → create-DEBgYRlM.mjs} +5 -5
- package/dist/{create-CN24yp_W.mjs → create-DJm0YuLW.mjs} +3 -3
- package/dist/{create-CuYGZ4gu2.mjs → create-DmKwDQCY2.mjs} +5 -5
- package/dist/{create-branch-DWcxC30N.mjs → create-branch-BN5iH-GM.mjs} +4 -4
- package/dist/{create-BEE8uvz2.mjs → create-bvpl6Fn5.mjs} +6 -6
- package/dist/create-uanpKsPo.mjs +34 -0
- package/dist/{csv-CUQvcCEk.mjs → csv-BhuX9fwh.mjs} +4 -4
- package/dist/{current-task-D6P0eL21.mjs → current-task-BMt2NeqV.mjs} +4 -4
- package/dist/{dashboard-BudI952R.mjs → dashboard-Ct_ajSYI.mjs} +10 -10
- package/dist/{dashboard-CKUR8ZpQ.mjs → dashboard-D0hwTC-f.mjs} +11 -2
- package/dist/{dashboard-BlbNszi8.mjs → dashboard-DgK81azj.mjs} +1 -1
- package/dist/{database-B19qlLKZ.mjs → database-C3E9PZSx.mjs} +1 -1
- package/dist/{database-C8G6ZKG0.mjs → database-JtHTqSpq.mjs} +1 -1
- package/dist/{db-C7UTd-6P.mjs → db-B_LW2VE-.mjs} +7 -7
- package/dist/{delete-Ud6iliGM.mjs → delete-BOcPK_H9.mjs} +4 -4
- package/dist/{delete-_IHffP-A.mjs → delete-CowGO4rh.mjs} +4 -4
- package/dist/{delete-Ds-zGh9C.mjs → delete-D0f7VatX.mjs} +4 -4
- package/dist/{delete-DbZZKcYj.mjs → delete-D2bUV6uo.mjs} +4 -4
- package/dist/delete-DZ_ICQug.mjs +44 -0
- package/dist/{delete-DSxqbcFE.mjs → delete-Ur7b11no.mjs} +4 -4
- package/dist/{delete-runtime-BjHL1ryM.mjs → delete-runtime-BKEzJn22.mjs} +1 -1
- package/dist/{delete-table-DtXH6IN5.mjs → delete-table-Dd8X573t.mjs} +4 -4
- package/dist/{dependencies-CR1dlq-A.mjs → dependencies-XDVLBwko.mjs} +6 -6
- package/dist/{dirty-CYxnOnh0.mjs → dirty-k-JmGLsS.mjs} +5 -5
- package/dist/{document-Cd2mmqCp.mjs → document-BHpLJbKU.mjs} +5 -0
- package/dist/document-BW9iow8R.mjs +19 -0
- package/dist/{document-D6OybtP2.mjs → document-CA0Q6lqu.mjs} +1 -1
- package/dist/{download-DPpmmYQe.mjs → download-CQjPIYDO.mjs} +2 -2
- package/dist/{eid-D-BbtWjt.mjs → eid-CNTKDgwj.mjs} +3 -3
- package/dist/{events-CJEnn8WE.mjs → events-BshWlkDp.mjs} +4 -4
- package/dist/{export-BOgyuIOQ.mjs → export-Dq6ecU8h.mjs} +6 -6
- package/dist/{field-CzHBOPER.mjs → field-Bo2ISMO4.mjs} +5 -5
- package/dist/{field-Cr2DPUG9.mjs → field-CcN4oZy6.mjs} +16 -1
- package/dist/{field-BPsNa-TO.mjs → field-fDtIrY6D.mjs} +1 -1
- package/dist/{fields-Bwgkrvus.mjs → fields-CVctqn5G.mjs} +6 -6
- package/dist/{get-BLJSCw53.mjs → get-7xTeNGAo.mjs} +5 -5
- package/dist/{get-DyyPiiaB.mjs → get-8b5Sh50q.mjs} +5 -5
- package/dist/{get-DVi3a2nm.mjs → get-B4RgW-VT.mjs} +5 -5
- package/dist/{get-BaPadzdM.mjs → get-BD81MHl_.mjs} +3 -3
- package/dist/{get-CvIgxPXV.mjs → get-Bl3OmlBP.mjs} +4 -4
- package/dist/get-BtTetWzm.mjs +32 -0
- package/dist/{get-BfVCLBqc.mjs → get-BvSA_mmf.mjs} +5 -5
- package/dist/{get-DsKmZfM2.mjs → get-BvgEF--n.mjs} +3 -3
- package/dist/{get-D8lHwu4-.mjs → get-C5sWciaE.mjs} +5 -5
- package/dist/{get-CqQ-pf0q.mjs → get-CO6X4nZH.mjs} +16 -12
- package/dist/{get-CWfIiXwL.mjs → get-CTPvdcud.mjs} +5 -5
- package/dist/{get-C1ZdOvMm.mjs → get-CrpwxWOV.mjs} +3 -3
- package/dist/{get-BOLwso0V.mjs → get-D4oGhZWX.mjs} +3 -3
- package/dist/{get-B89DUSvw.mjs → get-Df6cGHCM.mjs} +3 -3
- package/dist/{get-BL90QC64.mjs → get-DfMVlz64.mjs} +5 -5
- package/dist/{get-CLu4yzMp2.mjs → get-Dr-U321T2.mjs} +5 -5
- package/dist/{get-D4OTJblo.mjs → get-Dw7jAno3.mjs} +5 -5
- package/dist/{get-DgnYF7LR.mjs → get-PWhOdz1z.mjs} +3 -3
- package/dist/{get-COwdtskS.mjs → get-RslzBaXx.mjs} +4 -4
- package/dist/{get-run-Iya0Yw9s.mjs → get-run-CZdDqfUj.mjs} +5 -5
- package/dist/{get-Eqq13YY-.mjs → get-wjIgUlNl.mjs} +3 -3
- package/dist/git-sync-BmoRk0UV.mjs +28 -0
- package/dist/{git-sync-BDnxPrqU.mjs → git-sync-BwBRmEhE.mjs} +18 -1
- package/dist/{git-sync-DxD_ng48.mjs → git-sync-TjX1r_wF.mjs} +1 -1
- package/dist/{group-CmVCLBDz.mjs → group-YQQ5GIcP.mjs} +2 -3
- package/dist/{has-remote-changes-DfJUMP8F.mjs → has-remote-changes-i-3MVxat.mjs} +4 -4
- package/dist/{import-FEAx-Y5A.mjs → import-DWEKejya.mjs} +6 -6
- package/dist/{input-DFZ_qGW_.mjs → input-DEvkIjGr.mjs} +1 -1
- package/dist/{is-dirty-BsYjBSXG.mjs → is-dirty-C5ipqd4v.mjs} +2 -2
- package/dist/{items-D4rstE12.mjs → items-hKJ2ZDwy.mjs} +6 -6
- package/dist/{key-BmWundO3.mjs → key-PYetuQ13.mjs} +1 -1
- package/dist/{library-uzyHWBap.mjs → library-B7_04UVK.mjs} +5 -5
- package/dist/{library-DXB8sm4r.mjs → library-BPIzb3K_.mjs} +1 -1
- package/dist/{library-CmctxHjv.mjs → library-PGCfm0UA.mjs} +1 -1
- package/dist/{list-DrS3ePsv.mjs → list-1vdClKSE.mjs} +3 -3
- package/dist/{list-xMfCeuZc.mjs → list-6myofqMv.mjs} +6 -6
- package/dist/{list-squb_ioH.mjs → list-B-9QOX9Y.mjs} +5 -5
- package/dist/{list-ndIl9XqV.mjs → list-Bs7_Rysg.mjs} +6 -6
- package/dist/list-CHuhMXet.mjs +35 -0
- package/dist/{list-CQy0z7f9.mjs → list-CLZU_EOf.mjs} +3 -3
- package/dist/{list-DeNGm9G4.mjs → list-Cen-7uTo.mjs} +4 -4
- package/dist/{list-Bjj0z5BS.mjs → list-CgH-H-O6.mjs} +3 -3
- package/dist/{list-BmMi_wPD.mjs → list-CjNXskB4.mjs} +6 -6
- package/dist/{list-DoTiQc3D.mjs → list-CmFh1GQ_.mjs} +3 -3
- package/dist/{list-D_zvX0ms.mjs → list-D6tTvYUP.mjs} +3 -3
- package/dist/{list-CC1M_n6Z.mjs → list-DI820W6w.mjs} +5 -5
- package/dist/{list-Dgm6TkqR.mjs → list-DKZnQ4Ts.mjs} +6 -6
- package/dist/{list-sQcA4g05.mjs → list-DKcC4cm0.mjs} +5 -5
- package/dist/{list-BRpPbvyS.mjs → list-DfRqNH1N.mjs} +3 -3
- package/dist/{list-bN0RC14-.mjs → list-DjwnsyXM.mjs} +11 -10
- package/dist/{list-BXL8HFr_.mjs → list-VNC-_E59.mjs} +5 -5
- package/dist/{list-1DkkU82x.mjs → list-eKDT1XXk.mjs} +5 -5
- package/dist/{list-B7tqNV8B.mjs → list-oX2SMzxZ.mjs} +3 -3
- package/dist/{login-D_1-zE4A.mjs → login-DumZaWXK.mjs} +9 -9
- package/dist/{logout-DPi2q1Wu.mjs → logout-BsXPRc-3.mjs} +2 -2
- package/dist/{measure-CdA8Nl3Z.mjs → measure-BFxkbAoa.mjs} +6 -6
- package/dist/{notification-Fcq1fIPw.mjs → notification-DVrLkjFT.mjs} +1 -1
- package/dist/{parameter-DUKR8NXo.mjs → parameter-Celg0wZa.mjs} +1 -1
- package/dist/{parameter-values-C6dj6I4g.mjs → parameter-values-CoF9Hx1p.mjs} +4 -4
- package/dist/{parse-enum-B1t8S194.mjs → parse-enum-Dc0dMZ3P.mjs} +1 -1
- package/dist/{parse-id-DR8aUSdL.mjs → parse-id-DmFJgpY6.mjs} +1 -1
- package/dist/{parse-ref-BJ_Q0tNW.mjs → parse-ref-DTDld_LJ.mjs} +1 -1
- package/dist/{path-B96DI8u2.mjs → path-BQ4lRDyN.mjs} +4 -4
- package/dist/{poll-By46YQ5J.mjs → poll-CZeXepUQ.mjs} +2 -2
- package/dist/{preflight-Bl1oitm8.mjs → preflight-BTQe4swo.mjs} +3 -3
- package/dist/{process-CcQM4qPv.mjs → process-CTrfxxaC.mjs} +1 -1
- package/dist/{publish-BKJYvxif.mjs → publish-CFB2Cc5A.mjs} +4 -4
- package/dist/{pulse-BmsDenXm.mjs → pulse-Dz0ocv0l.mjs} +1 -1
- package/dist/{pulse-DhG6I9mI.mjs → pulse-x0gFxWfG.mjs} +2 -2
- package/dist/{query-qBHjZQc_.mjs → query-BJbUnAHf.mjs} +9 -9
- package/dist/query-CV2KCS5O.mjs +114 -0
- package/dist/{query-result-DBDwk8TS.mjs → query-result-E4Q-Gra6.mjs} +1 -1
- package/dist/{remove-collection-BWFW7Rn6.mjs → remove-collection-D3yvKH3e.mjs} +5 -5
- package/dist/{render-DmykmrFB.mjs → render-BJRCs7rA.mjs} +4 -2
- package/dist/{replace-BmAqD3zY.mjs → replace-uj4WTqx_.mjs} +4 -4
- package/dist/{rescan-values-BrCLrihF.mjs → rescan-values-CzxQU318.mjs} +5 -5
- package/dist/{run-q5Y44Fxj.mjs → run-B2f_omHu.mjs} +3 -3
- package/dist/run-DlO1J1Sx.mjs +50 -0
- package/dist/{run-CtbzjDKY.mjs → run-yX2dtmE5.mjs} +5 -5
- package/dist/{runs-JFlbezkQ.mjs → runs-DzUO45wU.mjs} +6 -6
- package/dist/{runtime-BQiGgbgZ.mjs → runtime-arKqJqIT.mjs} +225 -68
- package/dist/{schema-tables-Bzx2ShyE.mjs → schema-tables-DZCNzuQ6.mjs} +6 -6
- package/dist/{schemas-ww5mU2AS.mjs → schemas-2ejqaVsG.mjs} +4 -4
- package/dist/{search-DFBwUc6d.mjs → search-BAXg-EJw.mjs} +2 -1
- package/dist/{search-J4RwCof-.mjs → search-DcihauDZ.mjs} +5 -5
- package/dist/{segment-XXTjU0eG.mjs → segment-BQT2poPG.mjs} +6 -6
- package/dist/{selectors-BAAZMi43.mjs → selectors-BzestDld.mjs} +3 -3
- package/dist/{send-BmpDlw9O.mjs → send-DMxoLFo7.mjs} +3 -3
- package/dist/{set-DUWrSza9.mjs → set-CDmiD0vv.mjs} +4 -4
- package/dist/{set-active-BiUlbNI5.mjs → set-active-RrvWR9NY.mjs} +3 -3
- package/dist/{setting-B1KBQN3M.mjs → setting-BiBLCcxz.mjs} +4 -4
- package/dist/{setup-CVaNVwOd.mjs → setup-DYsTzkWO.mjs} +3 -3
- package/dist/{signal-GhGmuHfx.mjs → signal-k7cm5N6h.mjs} +1 -1
- package/dist/{skill-list-DTnDhnL5.mjs → skill-list-D9_1Pmt7.mjs} +16 -9
- package/dist/{skills-DkDsSH5F.mjs → skills-BPHXUfeL.mjs} +75 -28
- package/dist/{skills-BWrAlj9l.mjs → skills-C3bxxC6a.mjs} +3 -3
- package/dist/snippet-BtfxE60H.mjs +19 -0
- package/dist/{stash-DMm8YF8V.mjs → stash-DdheS0Ad.mjs} +6 -6
- package/dist/{status-BzEQjQ_t.mjs → status-BuIzXRX1.mjs} +3 -3
- package/dist/{status-ClWsQD6v.mjs → status-CXouQJ31.mjs} +5 -5
- package/dist/{subscription-CdFn2hre.mjs → subscription-CJ8Igs1U.mjs} +6 -6
- package/dist/{subscriptions-DBda1pE5.mjs → subscriptions-D0NpGvCQ.mjs} +6 -6
- package/dist/{summary-B4GPiuqD.mjs → summary-D04S8gGj.mjs} +5 -5
- package/dist/{sync-schema-DsIM5g2U.mjs → sync-schema-DrA5zkdl.mjs} +6 -6
- package/dist/{sync-task-BACcrs0i.mjs → sync-task-BXeWuARG.mjs} +1 -1
- package/dist/{table-CsIJNPFf.mjs → table-C6h4tIRw.mjs} +1 -1
- package/dist/{table-CeeTJgQb.mjs → table-DfuY0N8e.mjs} +51 -4
- package/dist/{table-D4Alrrwh.mjs → table-Dntbz7Q2.mjs} +5 -5
- package/dist/timeline-8jwsldo3.mjs +21 -0
- package/dist/{timeline-event-DWIh3Tdt.mjs → timeline-event-BbB1xEdI.mjs} +6 -6
- package/dist/{transform-Bk0D0nIs.mjs → transform-CtqB1WYo.mjs} +2 -2
- package/dist/{transform-DpuG-ON3.mjs → transform-DiW7bREn.mjs} +43 -1
- package/dist/transform-job-B-1YAbvy.mjs +22 -0
- package/dist/transform-m6s4kkWU.mjs +28 -0
- package/dist/{transform-tag-DJ3_bksm.mjs → transform-tag-PjryheLF.mjs} +5 -5
- package/dist/transform-test-BjjCQ2xm.mjs +169 -0
- package/dist/transform-test-DSTkKKNC.mjs +16 -0
- package/dist/transform-test-gzDcbypy.mjs +25 -0
- package/dist/{transforms-Dg2MfB2a.mjs → transforms-CijX3VE7.mjs} +6 -6
- package/dist/{tree-BQL0f7YX.mjs → tree-Cmb3O6rH.mjs} +3 -3
- package/dist/{unpublish-DfSvb_Rs.mjs → unpublish-DkP_AcK5.mjs} +3 -3
- package/dist/{update-DBGaJDsj.mjs → update-8UmD1prT.mjs} +6 -6
- package/dist/{update-Izqip6jY.mjs → update-BFyRBc-H.mjs} +7 -7
- package/dist/{update-BCgAyfj_.mjs → update-BrXGg3QO.mjs} +7 -7
- package/dist/{update-sYLQIUgh.mjs → update-C91m9YAR.mjs} +5 -5
- package/dist/{update-D1QdfpKR.mjs → update-COcx61Ur.mjs} +5 -5
- package/dist/update-Ci8YL4_2.mjs +41 -0
- package/dist/{update-CDo0Orvu.mjs → update-CtLbFCd_.mjs} +4 -4
- package/dist/{update-Bhmli02m.mjs → update-D6Zzvc7F.mjs} +6 -6
- package/dist/{update-Cr5zHb0D.mjs → update-D8htjzNJ.mjs} +4 -4
- package/dist/{update-CtDHMxW8.mjs → update-D9kOTr0n.mjs} +5 -5
- package/dist/{update-BxIyFtrX.mjs → update-DPTio6i1.mjs} +6 -6
- package/dist/{update-NZhIjTCf.mjs → update-DlWB9s0v.mjs} +4 -4
- package/dist/{update-D4qdTlLF.mjs → update-DubrpPbz.mjs} +4 -4
- package/dist/{update-CiYxcf8M.mjs → update-Dz47cKBk.mjs} +4 -4
- package/dist/{update-B-hRR8gW.mjs → update-FCP5Lop2.mjs} +6 -6
- package/dist/{update-CKoBDTL7.mjs → update-KSHnb6vB.mjs} +8 -8
- package/dist/{update-dashcard-D5b971AO.mjs → update-dashcard-BlibHa5o.mjs} +6 -6
- package/dist/{upgrade-CD1xtsIv.mjs → upgrade-EwL6wPSY.mjs} +4 -4
- package/dist/upload-BZshRJIM.mjs +13 -0
- package/dist/{upload-akKFxpVA.mjs → upload-D0KaTqUE.mjs} +3 -3
- package/dist/{upload-BUd3MG90.mjs → upload-Do2PBSeH.mjs} +2 -2
- package/dist/{uuid-oVdJ62eA.mjs → uuid-DjKLDIVE.mjs} +9 -5
- package/dist/{validate-query-Boi8-cAP.mjs → validate-query-D6_ad-Gi.mjs} +3 -3
- package/dist/{validate-CWd6l6KZ.mjs → validate-xR_MHBNR.mjs} +69 -23
- package/dist/{values-DLwZl-P8.mjs → values-Dc9612_L.mjs} +5 -5
- package/dist/{verify-CH9Tw8yv.mjs → verify-DVN1eqXZ.mjs} +3 -3
- package/dist/{wait-rfTdQWdi.mjs → wait-C-ovOTAZ.mjs} +6 -6
- package/dist/{wait-flags-DiQ_kRjZ.mjs → wait-flags-BQNmuvIj.mjs} +2 -2
- package/dist/{window-BkvrP0gB.mjs → window-DSb1tqSe.mjs} +1 -1
- package/package.json +1 -1
- package/skill-data/core/SKILL.md +20 -14
- package/skill-data/dashboard/SKILL.md +1 -1
- package/skill-data/mbql/SKILL.md +84 -115
- package/skill-data/mbql/references/operators.md +81 -240
- package/skill-data/native-sql/SKILL.md +8 -9
- package/skill-data/native-sql/references/template-tags.md +21 -25
- package/skill-data/transform/SKILL.md +64 -2
- package/skill-data/transform-test-plan/SKILL.md +171 -0
- package/skill-data/transform-test-plan/references/checklist.md +81 -0
- package/skill-data/transform-test-plan/references/checks.md +260 -0
- package/skill-data/visualization/SKILL.md +2 -3
- package/skill-data/visualization/references/settings.md +7 -7
- package/skills/metabase-cli/SKILL.md +1 -1
- package/dist/card-BRarvKYX.mjs +0 -24
- package/dist/collection-CKeO8X7U.mjs +0 -20
- package/dist/document-BoILnE_1.mjs +0 -19
- package/dist/git-sync-CdN0Maun.mjs +0 -28
- package/dist/query-BKSM-pbi.mjs +0 -86
- package/dist/snippet-CG75L2DS.mjs +0 -19
- package/dist/timeline-DmM0BuX8.mjs +0 -21
- package/dist/transform-BcV_XlSX.mjs +0 -28
- package/dist/transform-job-CjtwBGoM.mjs +0 -22
- package/dist/upload-DzGTlldn.mjs +0 -13
|
@@ -1,31 +1,32 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as InternalError, Q as ConfigError, at as ValidationError, n as methodRequirements, nt as ResponseShapeError, ot as errorMessage, rt as TimeoutError, tt as NetworkError } from "./cli.mjs";
|
|
2
2
|
import { n as Notification, r as NotificationCardPayload, t as CARD_PAYLOAD_TYPE } from "./notification-DaA4bBHW.mjs";
|
|
3
|
-
import { $ as
|
|
4
|
-
import { n as throwIfAborted, r as untilAborted, t as combineAborts } from "./signal-
|
|
5
|
-
import {
|
|
6
|
-
import { r as ParameterValues } from "./parameter-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { $ as createServerProfile, B as JSON_CONTENT_TYPE, F as buildNetworkError, G as credentialSecrets, H as parseJsonOrPlain, I as isConnectionClosed, J as normalizeUrl, L as HttpError, U as assertCredentialHeaderSafe, V as parseJson, W as credentialAuthHeader, Z as checkFeatures, et as probeServer, tt as CapabilityError, z as isRetryableStatus } from "./runtime-arKqJqIT.mjs";
|
|
4
|
+
import { n as throwIfAborted, r as untilAborted, t as combineAborts } from "./signal-k7cm5N6h.mjs";
|
|
5
|
+
import { a as FieldSearchMatches, i as FieldRemappedValue, l as FieldValues, n as FieldBaseType, o as FieldSemanticType, t as Field } from "./field-CcN4oZy6.mjs";
|
|
6
|
+
import { a as TemporalUnit, r as ParameterValues } from "./parameter-Celg0wZa.mjs";
|
|
7
|
+
import { a as CardQueryResult, l as DatasetQuery, s as CardType, t as Card } from "./card-voh1k4hl.mjs";
|
|
8
|
+
import { c as TableVisibilityType, i as TableForeignKey, o as TableQueryMetadata, r as TableDataLayerTier, t as Table } from "./table-DfuY0N8e.mjs";
|
|
9
|
+
import { t as Database } from "./database-JtHTqSpq.mjs";
|
|
10
|
+
import { t as Snippet } from "./snippet-CyKAgIZl.mjs";
|
|
11
|
+
import { c as CollectionItem, i as CollectionAuthorityLevel, m as CollectionTreeNode, r as Collection, s as CollectionId } from "./collection-BxdPxD38.mjs";
|
|
9
12
|
import { t as ContentTranslationUploadResult } from "./content-translation-BrHOrmj9.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { t as
|
|
13
|
-
import { r as pollUntil } from "./poll-By46YQ5J.mjs";
|
|
14
|
-
import { t as Document } from "./document-Cd2mmqCp.mjs";
|
|
13
|
+
import { a as DashboardDetail, c as Dashcard, r as DashboardCopy, t as Dashboard } from "./dashboard-D0hwTC-f.mjs";
|
|
14
|
+
import { r as pollUntil } from "./poll-CZeXepUQ.mjs";
|
|
15
|
+
import { t as Document } from "./document-BHpLJbKU.mjs";
|
|
15
16
|
import { i as EidTranslateResult } from "./eid-translation-zEHtr5Oc.mjs";
|
|
16
|
-
import {
|
|
17
|
-
import { a as toLibrary, i as libraryWireSchema, n as LibraryCollectionInfo } from "./library-
|
|
17
|
+
import { c as SyncSettingsUpdateResult, i as SyncExportPreflight, n as SyncDirtyItem, p as isSyncTaskTerminal, s as SyncRemoteChanges, t as SyncBranchCreated, u as SyncTask } from "./git-sync-BwBRmEhE.mjs";
|
|
18
|
+
import { a as toLibrary, i as libraryWireSchema, n as LibraryCollectionInfo } from "./library-BPIzb3K_.mjs";
|
|
18
19
|
import { t as Measure } from "./measure-CtfjqJFP.mjs";
|
|
19
|
-
import { t as Pulse } from "./pulse-
|
|
20
|
-
import {
|
|
20
|
+
import { t as Pulse } from "./pulse-Dz0ocv0l.mjs";
|
|
21
|
+
import { a as TransformDagTransform, d as TransformTarget, g as transformRowSchema, h as transformDetailSchema, i as TransformDagRunResult, l as TransformRunSummary, m as isTransformRunTerminal, o as TransformRun, p as isTransformRunFailed, u as TransformSourceTableEntry } from "./transform-DiW7bREn.mjs";
|
|
22
|
+
import { r as SearchResult } from "./search-BAXg-EJw.mjs";
|
|
21
23
|
import { t as Segment } from "./segment-OsrbUDzw.mjs";
|
|
22
24
|
import { t as Setting } from "./setting-DTiLCW8g.mjs";
|
|
23
25
|
import { n as SetupResult } from "./setup-CO7QV-ao.mjs";
|
|
24
|
-
import { t as Snippet } from "./snippet-CyKAgIZl.mjs";
|
|
25
26
|
import { i as TimelineEvent, t as Timeline } from "./timeline-CCSU2qOS.mjs";
|
|
26
|
-
import { d as transformDetailSchema, f as transformRowSchema, i as TransformRun, l as isTransformRunFailed, u as isTransformRunTerminal } from "./transform-DpuG-ON3.mjs";
|
|
27
27
|
import { c as transformJobSchema, n as TransformJobActiveResult, s as transformJobRunResultSchema } from "./transform-job-CCguL6LP.mjs";
|
|
28
28
|
import { t as TransformTag } from "./transform-tag-CcElGp3C.mjs";
|
|
29
|
+
import { i as TransformTestRunResult, t as TransformTest } from "./transform-test-BjjCQ2xm.mjs";
|
|
29
30
|
import { t as UploadResult } from "./upload-DAtxBBms.mjs";
|
|
30
31
|
import { z } from "zod";
|
|
31
32
|
import { setTimeout } from "node:timers/promises";
|
|
@@ -261,14 +262,18 @@ function createTransport(config, options) {
|
|
|
261
262
|
return untilAborted(serverProfile, wait.signal);
|
|
262
263
|
}
|
|
263
264
|
const enforceRequirements = options.enforceRequirements ?? true;
|
|
264
|
-
async function requireFeatures(
|
|
265
|
-
if (!enforceRequirements ||
|
|
266
|
-
const failure =
|
|
265
|
+
async function requireFeatures(features, wait = {}) {
|
|
266
|
+
if (!enforceRequirements || features.length === 0) return;
|
|
267
|
+
const failure = checkFeatures(features, await server(wait));
|
|
267
268
|
if (failure !== null) throw new CapabilityError(failure);
|
|
268
269
|
}
|
|
270
|
+
async function requireMethod(key, wait = {}) {
|
|
271
|
+
return requireFeatures(methodRequirements(key), wait);
|
|
272
|
+
}
|
|
269
273
|
const transport = {
|
|
270
274
|
server,
|
|
271
|
-
require:
|
|
275
|
+
require: requireMethod,
|
|
276
|
+
requireFeatures,
|
|
272
277
|
async requestRaw(path, opts) {
|
|
273
278
|
return (await executeWithAuthRefresh(path, opts ?? {})).response;
|
|
274
279
|
},
|
|
@@ -301,8 +306,7 @@ function createTransport(config, options) {
|
|
|
301
306
|
return transport;
|
|
302
307
|
}
|
|
303
308
|
function tagOf(profile) {
|
|
304
|
-
|
|
305
|
-
return profile.version.tag;
|
|
309
|
+
return profile === null ? null : profile.version.tag;
|
|
306
310
|
}
|
|
307
311
|
function buildUrl(baseUrl, path, query) {
|
|
308
312
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
@@ -346,6 +350,44 @@ async function readBodyForError(response) {
|
|
|
346
350
|
}
|
|
347
351
|
}
|
|
348
352
|
//#endregion
|
|
353
|
+
//#region ../client/src/domain/dataset.ts
|
|
354
|
+
const CompiledQuery = z.object({
|
|
355
|
+
query: z.union([z.string(), z.array(z.unknown())]),
|
|
356
|
+
params: z.array(z.unknown()).nullable().optional(),
|
|
357
|
+
collection: z.string().optional()
|
|
358
|
+
}).loose();
|
|
359
|
+
const FieldRef = z.tuple([
|
|
360
|
+
z.literal("field"),
|
|
361
|
+
z.string(),
|
|
362
|
+
z.object({ "base-type": FieldBaseType }).loose()
|
|
363
|
+
]);
|
|
364
|
+
const VirtualField = z.object({
|
|
365
|
+
id: z.union([z.number().int(), FieldRef]),
|
|
366
|
+
table_id: z.string(),
|
|
367
|
+
name: z.string(),
|
|
368
|
+
display_name: z.string(),
|
|
369
|
+
base_type: FieldBaseType,
|
|
370
|
+
semantic_type: FieldSemanticType.nullable(),
|
|
371
|
+
fk_target_field_id: z.number().int().nullable().optional()
|
|
372
|
+
}).loose();
|
|
373
|
+
const VirtualTable = z.object({
|
|
374
|
+
id: z.string(),
|
|
375
|
+
db_id: z.number().int(),
|
|
376
|
+
display_name: z.string(),
|
|
377
|
+
schema: z.string(),
|
|
378
|
+
description: z.string().nullable(),
|
|
379
|
+
type: CardType,
|
|
380
|
+
moderated_status: z.string().nullable(),
|
|
381
|
+
entity_id: z.string().nullable(),
|
|
382
|
+
fields: z.array(VirtualField)
|
|
383
|
+
}).loose();
|
|
384
|
+
const QueryMetadata = z.object({
|
|
385
|
+
databases: z.array(Database),
|
|
386
|
+
tables: z.array(z.union([TableQueryMetadata, VirtualTable])),
|
|
387
|
+
fields: z.array(Field),
|
|
388
|
+
snippets: z.array(Snippet)
|
|
389
|
+
}).loose();
|
|
390
|
+
//#endregion
|
|
349
391
|
//#region ../client/src/resources/card.ts
|
|
350
392
|
const CardApiList = z.array(Card);
|
|
351
393
|
function cardResource(transport) {
|
|
@@ -417,6 +459,14 @@ function cardResource(transport) {
|
|
|
417
459
|
body
|
|
418
460
|
});
|
|
419
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Get all of the required query metadata for a saved card: the databases, tables, fields and
|
|
464
|
+
* snippets its query references, plus the card's own metadata for a model or a native query.
|
|
465
|
+
*/
|
|
466
|
+
async function queryMetadata(id, options = {}) {
|
|
467
|
+
await transport.require("card.queryMetadata", options);
|
|
468
|
+
return transport.requestParsed(QueryMetadata, `/api/card/${id}/query_metadata`, { ...options });
|
|
469
|
+
}
|
|
420
470
|
return {
|
|
421
471
|
list,
|
|
422
472
|
get,
|
|
@@ -424,7 +474,8 @@ function cardResource(transport) {
|
|
|
424
474
|
update,
|
|
425
475
|
archive,
|
|
426
476
|
query,
|
|
427
|
-
exportQuery
|
|
477
|
+
exportQuery,
|
|
478
|
+
queryMetadata
|
|
428
479
|
};
|
|
429
480
|
}
|
|
430
481
|
async function* paginatePages(client, path, itemSchema, opts = {}) {
|
|
@@ -664,6 +715,20 @@ function dashboardResource(transport) {
|
|
|
664
715
|
});
|
|
665
716
|
}
|
|
666
717
|
/**
|
|
718
|
+
* Copy a dashboard, with its tabs and dashcards, into `collection_id` (root when absent). A deep
|
|
719
|
+
* copy duplicates the cards it can; otherwise the copy references them, except dashboard
|
|
720
|
+
* questions, which are always duplicated. Cards the caller cannot read are left behind and
|
|
721
|
+
* reported as `uncopied`.
|
|
722
|
+
*/
|
|
723
|
+
async function copy(id, params = {}, options = {}) {
|
|
724
|
+
await transport.require("dashboard.copy", options);
|
|
725
|
+
return transport.requestParsed(DashboardCopy, `/api/dashboard/${id}/copy`, {
|
|
726
|
+
...options,
|
|
727
|
+
method: "POST",
|
|
728
|
+
body: params
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
667
732
|
* Archive (soft-delete) a dashboard by id. Metabase models this as an update, not its own
|
|
668
733
|
* endpoint. The answer is read as `Dashboard` rather than the `DashboardDetail` `update` returns:
|
|
669
734
|
* an archive is a state change on the dashboard itself, and its dashcards are not part of it.
|
|
@@ -750,6 +815,7 @@ function dashboardResource(transport) {
|
|
|
750
815
|
create,
|
|
751
816
|
update,
|
|
752
817
|
archive,
|
|
818
|
+
copy,
|
|
753
819
|
updateDashcard,
|
|
754
820
|
checkCardReferences,
|
|
755
821
|
parameterValues,
|
|
@@ -900,7 +966,298 @@ function datasetResource(transport) {
|
|
|
900
966
|
body
|
|
901
967
|
});
|
|
902
968
|
}
|
|
903
|
-
|
|
969
|
+
/**
|
|
970
|
+
* Fetch a native version of an MBQL query. `pretty` rides in the same body as the query and
|
|
971
|
+
* defaults server-side to true.
|
|
972
|
+
*/
|
|
973
|
+
async function native(datasetQuery, params = {}, options = {}) {
|
|
974
|
+
await transport.require("dataset.native", options);
|
|
975
|
+
return transport.requestParsed(CompiledQuery, "/api/dataset/native", {
|
|
976
|
+
...options,
|
|
977
|
+
method: "POST",
|
|
978
|
+
body: {
|
|
979
|
+
...datasetQuery,
|
|
980
|
+
pretty: params.pretty
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Get all of the required query metadata for an ad-hoc query: the databases, tables, fields and
|
|
986
|
+
* snippets it references. `{ settings: { "include-sensitive-fields": true } }` inside the query
|
|
987
|
+
* widens the field filter.
|
|
988
|
+
*/
|
|
989
|
+
async function queryMetadata(datasetQuery, options = {}) {
|
|
990
|
+
await transport.require("dataset.queryMetadata", options);
|
|
991
|
+
return transport.requestParsed(QueryMetadata, "/api/dataset/query_metadata", {
|
|
992
|
+
...options,
|
|
993
|
+
method: "POST",
|
|
994
|
+
body: datasetQuery
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Run an ad-hoc query and stream its result as a download. Unlike `query`, this endpoint answers
|
|
999
|
+
* bytes, so a caller consumes the stream rather than a value.
|
|
1000
|
+
*/
|
|
1001
|
+
async function exportQuery(format, params, options = {}) {
|
|
1002
|
+
await transport.require("dataset.exportQuery", options);
|
|
1003
|
+
return transport.requestStream(`/api/dataset/${format}`, {
|
|
1004
|
+
...options,
|
|
1005
|
+
method: "POST",
|
|
1006
|
+
body: {
|
|
1007
|
+
query: params.query,
|
|
1008
|
+
format_rows: params.format_rows,
|
|
1009
|
+
pivot_results: params.pivot_results
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
return {
|
|
1014
|
+
query,
|
|
1015
|
+
native,
|
|
1016
|
+
queryMetadata,
|
|
1017
|
+
exportQuery
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
//#endregion
|
|
1021
|
+
//#region ../client/src/domain/dependency.ts
|
|
1022
|
+
const DependencyType = z.enum([
|
|
1023
|
+
"table",
|
|
1024
|
+
"card",
|
|
1025
|
+
"snippet",
|
|
1026
|
+
"transform",
|
|
1027
|
+
"dashboard",
|
|
1028
|
+
"document",
|
|
1029
|
+
"sandbox",
|
|
1030
|
+
"segment",
|
|
1031
|
+
"measure"
|
|
1032
|
+
]);
|
|
1033
|
+
const DependencyUsageType = z.enum([
|
|
1034
|
+
"table",
|
|
1035
|
+
"snippet",
|
|
1036
|
+
"transform",
|
|
1037
|
+
"dashboard",
|
|
1038
|
+
"document",
|
|
1039
|
+
"sandbox",
|
|
1040
|
+
"segment",
|
|
1041
|
+
"question",
|
|
1042
|
+
"model",
|
|
1043
|
+
"metric",
|
|
1044
|
+
"measure"
|
|
1045
|
+
]);
|
|
1046
|
+
const DependencyFindingErrorType = z.enum([
|
|
1047
|
+
"missing-column",
|
|
1048
|
+
"missing-table-alias",
|
|
1049
|
+
"missing-table",
|
|
1050
|
+
"missing-card",
|
|
1051
|
+
"duplicate-column",
|
|
1052
|
+
"syntax-error",
|
|
1053
|
+
"validation-exception-error"
|
|
1054
|
+
]);
|
|
1055
|
+
const DependencyErrorSourceType = z.enum([
|
|
1056
|
+
"table",
|
|
1057
|
+
"card",
|
|
1058
|
+
"transform"
|
|
1059
|
+
]);
|
|
1060
|
+
z.enum([
|
|
1061
|
+
"name",
|
|
1062
|
+
"location",
|
|
1063
|
+
"view-count"
|
|
1064
|
+
]);
|
|
1065
|
+
z.enum([
|
|
1066
|
+
"name",
|
|
1067
|
+
"location",
|
|
1068
|
+
"dependents-with-errors",
|
|
1069
|
+
"dependents-errors"
|
|
1070
|
+
]);
|
|
1071
|
+
const DependencyCollectionRef = z.object({
|
|
1072
|
+
id: CollectionId,
|
|
1073
|
+
name: z.string(),
|
|
1074
|
+
authority_level: CollectionAuthorityLevel.nullable(),
|
|
1075
|
+
is_personal: z.boolean().optional()
|
|
1076
|
+
}).loose();
|
|
1077
|
+
const DependencyContainerRef = z.object({
|
|
1078
|
+
id: z.number().int(),
|
|
1079
|
+
name: z.string()
|
|
1080
|
+
}).loose();
|
|
1081
|
+
const DependencyEntityData = z.object({
|
|
1082
|
+
name: z.string().nullable().optional(),
|
|
1083
|
+
display_name: z.string().nullable().optional(),
|
|
1084
|
+
description: z.string().nullable().optional(),
|
|
1085
|
+
type: CardType.nullable().optional(),
|
|
1086
|
+
display: z.string().nullable().optional(),
|
|
1087
|
+
database_id: z.number().int().nullable().optional(),
|
|
1088
|
+
db_id: z.number().int().nullable().optional(),
|
|
1089
|
+
schema: z.string().nullable().optional(),
|
|
1090
|
+
collection_id: CollectionId.nullable().optional(),
|
|
1091
|
+
collection: DependencyCollectionRef.nullable().optional(),
|
|
1092
|
+
dashboard_id: z.number().int().nullable().optional(),
|
|
1093
|
+
dashboard: DependencyContainerRef.nullable().optional(),
|
|
1094
|
+
document_id: z.number().int().nullable().optional(),
|
|
1095
|
+
document: DependencyContainerRef.nullable().optional(),
|
|
1096
|
+
table_id: z.number().int().nullable().optional(),
|
|
1097
|
+
view_count: z.number().int().nullable().optional()
|
|
1098
|
+
}).loose();
|
|
1099
|
+
const DependencyEntity = z.object({
|
|
1100
|
+
id: z.number().int(),
|
|
1101
|
+
type: DependencyType,
|
|
1102
|
+
data: DependencyEntityData
|
|
1103
|
+
}).loose();
|
|
1104
|
+
const DependencyNode = DependencyEntity.extend({ dependents_count: z.partialRecord(DependencyUsageType, z.number().int()).nullable() });
|
|
1105
|
+
const DependencyFindingError = z.object({
|
|
1106
|
+
id: z.number().int(),
|
|
1107
|
+
analyzed_entity_type: DependencyType,
|
|
1108
|
+
analyzed_entity_id: z.number().int(),
|
|
1109
|
+
error_type: DependencyFindingErrorType,
|
|
1110
|
+
error_detail: z.string().nullable().optional(),
|
|
1111
|
+
source_entity_type: DependencyErrorSourceType.nullable().optional(),
|
|
1112
|
+
source_entity_id: z.number().int().nullable().optional()
|
|
1113
|
+
}).loose();
|
|
1114
|
+
const BreakingSource = DependencyNode.extend({ dependents_errors: z.array(DependencyFindingError).nullable().optional() });
|
|
1115
|
+
const DependencyEdge = z.object({
|
|
1116
|
+
from_entity_type: DependencyType,
|
|
1117
|
+
from_entity_id: z.number().int(),
|
|
1118
|
+
to_entity_type: DependencyType,
|
|
1119
|
+
to_entity_id: z.number().int()
|
|
1120
|
+
}).loose();
|
|
1121
|
+
const DependencyGraph = z.object({
|
|
1122
|
+
nodes: z.array(DependencyNode),
|
|
1123
|
+
edges: z.array(DependencyEdge)
|
|
1124
|
+
}).loose();
|
|
1125
|
+
//#endregion
|
|
1126
|
+
//#region ../client/src/resources/dependency.ts
|
|
1127
|
+
const DependencyNodeApiList = z.array(DependencyNode);
|
|
1128
|
+
const DependencyEntityApiList = z.array(DependencyEntity);
|
|
1129
|
+
const RENAMED_FILTERS = [
|
|
1130
|
+
"dependent-types",
|
|
1131
|
+
"dependent-card-types",
|
|
1132
|
+
"card-types",
|
|
1133
|
+
"include-personal-collections",
|
|
1134
|
+
"sort-column",
|
|
1135
|
+
"sort-direction"
|
|
1136
|
+
];
|
|
1137
|
+
function filterFeatures(params) {
|
|
1138
|
+
return RENAMED_FILTERS.some((key) => params[key] !== void 0) ? ["dependencyKebabCaseFilters"] : [];
|
|
1139
|
+
}
|
|
1140
|
+
function dependencyResource(transport) {
|
|
1141
|
+
/**
|
|
1142
|
+
* The upstream dependency graph of one entity. `nodes` holds the starting entity plus every
|
|
1143
|
+
* entity it depends on, directly or transitively; each edge runs from the dependent to what it
|
|
1144
|
+
* depends on.
|
|
1145
|
+
*/
|
|
1146
|
+
async function graph(type, id, options = {}) {
|
|
1147
|
+
await transport.require("dependency.graph", options);
|
|
1148
|
+
return transport.requestParsed(DependencyGraph, "/api/ee/dependencies/graph", {
|
|
1149
|
+
...options,
|
|
1150
|
+
query: {
|
|
1151
|
+
type,
|
|
1152
|
+
id
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* The entities that depend directly on one entity. `dependent-types` and `dependent-card-types`
|
|
1158
|
+
* narrow which kinds are listed, `broken` keeps only those whose query the entity has broken,
|
|
1159
|
+
* `query` matches against names and locations, `include-personal-collections` admits content in
|
|
1160
|
+
* personal collections, and `sort-column` / `sort-direction` order the result.
|
|
1161
|
+
*/
|
|
1162
|
+
async function dependents(type, id, params = {}, options = {}) {
|
|
1163
|
+
await transport.require("dependency.dependents", options);
|
|
1164
|
+
await transport.requireFeatures(filterFeatures(params), options);
|
|
1165
|
+
return {
|
|
1166
|
+
data: await transport.requestParsed(DependencyNodeApiList, "/api/ee/dependencies/graph/dependents", {
|
|
1167
|
+
...options,
|
|
1168
|
+
query: {
|
|
1169
|
+
type,
|
|
1170
|
+
id,
|
|
1171
|
+
"dependent-types": params["dependent-types"],
|
|
1172
|
+
"dependent-card-types": params["dependent-card-types"],
|
|
1173
|
+
broken: params.broken,
|
|
1174
|
+
query: params.query,
|
|
1175
|
+
"include-personal-collections": params["include-personal-collections"],
|
|
1176
|
+
"sort-column": params["sort-column"],
|
|
1177
|
+
"sort-direction": params["sort-direction"]
|
|
1178
|
+
}
|
|
1179
|
+
}),
|
|
1180
|
+
total: null
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* The dependents of one entity whose queries it has broken, as bare entities without a
|
|
1185
|
+
* dependents count. `dependent-types` and `dependent-card-types` narrow which kinds are listed,
|
|
1186
|
+
* `include-personal-collections` admits content in personal collections, and `sort-column` /
|
|
1187
|
+
* `sort-direction` order the result.
|
|
1188
|
+
*/
|
|
1189
|
+
async function broken(type, id, params = {}, options = {}) {
|
|
1190
|
+
await transport.require("dependency.broken", options);
|
|
1191
|
+
await transport.requireFeatures(filterFeatures(params), options);
|
|
1192
|
+
return {
|
|
1193
|
+
data: await transport.requestParsed(DependencyEntityApiList, "/api/ee/dependencies/graph/broken", {
|
|
1194
|
+
...options,
|
|
1195
|
+
query: {
|
|
1196
|
+
type,
|
|
1197
|
+
id,
|
|
1198
|
+
"dependent-types": params["dependent-types"],
|
|
1199
|
+
"dependent-card-types": params["dependent-card-types"],
|
|
1200
|
+
"include-personal-collections": params["include-personal-collections"],
|
|
1201
|
+
"sort-column": params["sort-column"],
|
|
1202
|
+
"sort-direction": params["sort-direction"]
|
|
1203
|
+
}
|
|
1204
|
+
}),
|
|
1205
|
+
total: null
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Walk the entities nothing depends on, one page at a time. `types` and `card-types` narrow
|
|
1210
|
+
* which kinds are listed, `query` matches against names and locations,
|
|
1211
|
+
* `include-personal-collections` admits content in personal collections, and `sort-column` /
|
|
1212
|
+
* `sort-direction` order the result. This endpoint pages on the server, so the caller consumes
|
|
1213
|
+
* pages and decides how far to pull.
|
|
1214
|
+
*/
|
|
1215
|
+
async function* unreferencedPages(params = {}, options = {}) {
|
|
1216
|
+
await transport.require("dependency.unreferencedPages", options);
|
|
1217
|
+
await transport.requireFeatures(filterFeatures(params), options);
|
|
1218
|
+
yield* paginatePages(transport, "/api/ee/dependencies/graph/unreferenced", DependencyNode, {
|
|
1219
|
+
query: itemListQuery(params),
|
|
1220
|
+
...options.offset !== void 0 && { offset: options.offset },
|
|
1221
|
+
...options.max !== void 0 && { max: options.max },
|
|
1222
|
+
...options.pageSize !== void 0 && { pageSize: options.pageSize },
|
|
1223
|
+
...options.signal !== void 0 && { signal: options.signal }
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Walk the entities whose dependents carry analysis errors, one page at a time, each with the
|
|
1228
|
+
* `dependents_errors` rows found downstream of it. The server lists cards and tables unless
|
|
1229
|
+
* `types` says otherwise; `card-types`, `query`, `include-personal-collections`, `sort-column`
|
|
1230
|
+
* and `sort-direction` read as on `unreferencedPages`. This endpoint pages on the server, so the
|
|
1231
|
+
* caller consumes pages and decides how far to pull.
|
|
1232
|
+
*/
|
|
1233
|
+
async function* breakingPages(params = {}, options = {}) {
|
|
1234
|
+
await transport.require("dependency.breakingPages", options);
|
|
1235
|
+
await transport.requireFeatures(filterFeatures(params), options);
|
|
1236
|
+
yield* paginatePages(transport, "/api/ee/dependencies/graph/breaking", BreakingSource, {
|
|
1237
|
+
query: itemListQuery(params),
|
|
1238
|
+
...options.offset !== void 0 && { offset: options.offset },
|
|
1239
|
+
...options.max !== void 0 && { max: options.max },
|
|
1240
|
+
...options.pageSize !== void 0 && { pageSize: options.pageSize },
|
|
1241
|
+
...options.signal !== void 0 && { signal: options.signal }
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
return {
|
|
1245
|
+
graph,
|
|
1246
|
+
dependents,
|
|
1247
|
+
broken,
|
|
1248
|
+
unreferencedPages,
|
|
1249
|
+
breakingPages
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
function itemListQuery(params) {
|
|
1253
|
+
return {
|
|
1254
|
+
types: params.types,
|
|
1255
|
+
"card-types": params["card-types"],
|
|
1256
|
+
query: params.query,
|
|
1257
|
+
"include-personal-collections": params["include-personal-collections"],
|
|
1258
|
+
"sort-column": params["sort-column"],
|
|
1259
|
+
"sort-direction": params["sort-direction"]
|
|
1260
|
+
};
|
|
904
1261
|
}
|
|
905
1262
|
//#endregion
|
|
906
1263
|
//#region ../client/src/resources/document.ts
|
|
@@ -942,12 +1299,25 @@ function documentResource(transport) {
|
|
|
942
1299
|
await transport.require("document.archive", options);
|
|
943
1300
|
return update(id, { archived: true }, options);
|
|
944
1301
|
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Copy a document into `collection_id` (root when absent), duplicating the cards saved inside
|
|
1304
|
+
* it. An archived source is not found.
|
|
1305
|
+
*/
|
|
1306
|
+
async function copy(id, params = {}, options = {}) {
|
|
1307
|
+
await transport.require("document.copy", options);
|
|
1308
|
+
return transport.requestParsed(Document, `/api/document/${id}/copy`, {
|
|
1309
|
+
...options,
|
|
1310
|
+
method: "POST",
|
|
1311
|
+
body: params
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
945
1314
|
return {
|
|
946
1315
|
list,
|
|
947
1316
|
get,
|
|
948
1317
|
create,
|
|
949
1318
|
update,
|
|
950
|
-
archive
|
|
1319
|
+
archive,
|
|
1320
|
+
copy
|
|
951
1321
|
};
|
|
952
1322
|
}
|
|
953
1323
|
//#endregion
|
|
@@ -969,6 +1339,82 @@ function eidTranslationResource(transport) {
|
|
|
969
1339
|
return { translate };
|
|
970
1340
|
}
|
|
971
1341
|
//#endregion
|
|
1342
|
+
//#region ../client/src/domain/erd.ts
|
|
1343
|
+
const ErdField = z.object({
|
|
1344
|
+
id: z.number().int(),
|
|
1345
|
+
name: z.string(),
|
|
1346
|
+
display_name: z.string(),
|
|
1347
|
+
database_type: z.string(),
|
|
1348
|
+
base_type: FieldBaseType.nullable(),
|
|
1349
|
+
effective_type: FieldBaseType.nullable(),
|
|
1350
|
+
semantic_type: FieldSemanticType.nullable(),
|
|
1351
|
+
fk_target_field_id: z.number().int().nullable(),
|
|
1352
|
+
fk_target_table_id: z.number().int().nullable()
|
|
1353
|
+
}).loose();
|
|
1354
|
+
const ErdOwner = z.object({
|
|
1355
|
+
id: z.number().int().optional(),
|
|
1356
|
+
email: z.string(),
|
|
1357
|
+
first_name: z.string().nullable().optional(),
|
|
1358
|
+
last_name: z.string().nullable().optional()
|
|
1359
|
+
}).loose().nullable();
|
|
1360
|
+
const ErdNode = z.object({
|
|
1361
|
+
table_id: z.number().int(),
|
|
1362
|
+
name: z.string(),
|
|
1363
|
+
display_name: z.string(),
|
|
1364
|
+
description: z.string().nullable(),
|
|
1365
|
+
owner: ErdOwner,
|
|
1366
|
+
schema: z.string().nullable(),
|
|
1367
|
+
visibility_type: TableVisibilityType.nullable(),
|
|
1368
|
+
db_id: z.number().int(),
|
|
1369
|
+
fields: z.array(ErdField)
|
|
1370
|
+
}).loose();
|
|
1371
|
+
const ErdEdge = z.object({
|
|
1372
|
+
source_table_id: z.number().int(),
|
|
1373
|
+
source_field_id: z.number().int(),
|
|
1374
|
+
target_table_id: z.number().int(),
|
|
1375
|
+
target_field_id: z.number().int(),
|
|
1376
|
+
relationship: z.enum(["one-to-one", "many-to-one"])
|
|
1377
|
+
}).loose();
|
|
1378
|
+
const Erd = z.object({
|
|
1379
|
+
nodes: z.array(ErdNode),
|
|
1380
|
+
edges: z.array(ErdEdge)
|
|
1381
|
+
}).loose();
|
|
1382
|
+
//#endregion
|
|
1383
|
+
//#region ../client/src/resources/erd.ts
|
|
1384
|
+
const ERD_PATH = "/api/ee/erd";
|
|
1385
|
+
function erdResource(transport) {
|
|
1386
|
+
/**
|
|
1387
|
+
* Get the entity relationship diagram of a database: the readable tables as nodes, each with its
|
|
1388
|
+
* fields, and the foreign keys between them as edges. `table-ids` makes those tables the focal
|
|
1389
|
+
* points and draws their neighbours; `schema` keeps one schema, the empty string the tables with
|
|
1390
|
+
* none.
|
|
1391
|
+
*/
|
|
1392
|
+
async function get(params, options = {}) {
|
|
1393
|
+
await transport.require("erd.get", options);
|
|
1394
|
+
return transport.requestParsed(Erd, ERD_PATH, {
|
|
1395
|
+
...options,
|
|
1396
|
+
query: {
|
|
1397
|
+
"database-id": params["database-id"],
|
|
1398
|
+
"table-ids": params["table-ids"],
|
|
1399
|
+
schema: params.schema
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
return { get };
|
|
1404
|
+
}
|
|
1405
|
+
//#endregion
|
|
1406
|
+
//#region ../client/src/resources/optional-parsed.ts
|
|
1407
|
+
const NO_CONTENT_STATUS = 204;
|
|
1408
|
+
async function fetchOptionalParsed(client, path, schema, options = {}) {
|
|
1409
|
+
const response = await client.requestRaw(path, {
|
|
1410
|
+
...options,
|
|
1411
|
+
method: "GET",
|
|
1412
|
+
expectContentType: "binary"
|
|
1413
|
+
});
|
|
1414
|
+
if (response.status === NO_CONTENT_STATUS) return null;
|
|
1415
|
+
return parseJsonOrPlain(await response.text(), response.headers.get("content-type"), schema, { source: response.url });
|
|
1416
|
+
}
|
|
1417
|
+
//#endregion
|
|
972
1418
|
//#region ../client/src/resources/field.ts
|
|
973
1419
|
const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
|
|
974
1420
|
function fieldResource(transport) {
|
|
@@ -977,15 +1423,47 @@ function fieldResource(transport) {
|
|
|
977
1423
|
await transport.require("field.get", options);
|
|
978
1424
|
return transport.requestParsed(Field, `/api/field/${id}`, { ...options });
|
|
979
1425
|
}
|
|
980
|
-
/**
|
|
1426
|
+
/**
|
|
1427
|
+
* Update a field by id, patching only the fields the body carries. A `data_sensitivity` label is
|
|
1428
|
+
* a person's call the server's classifier never overwrites, and `null` withdraws it so the
|
|
1429
|
+
* classifier's own applies again; a server without the column would drop the key silently, so
|
|
1430
|
+
* the label is refused there before the wire.
|
|
1431
|
+
*/
|
|
981
1432
|
async function update(id, params, options = {}) {
|
|
982
1433
|
await transport.require("field.update", options);
|
|
1434
|
+
await transport.requireFeatures(params.data_sensitivity === void 0 ? [] : ["fieldDataSensitivity"], options);
|
|
983
1435
|
return transport.requestParsed(Field, `/api/field/${id}`, {
|
|
984
1436
|
...options,
|
|
985
1437
|
method: "PUT",
|
|
986
1438
|
body: params
|
|
987
1439
|
});
|
|
988
1440
|
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Search the values of `searchId` that contain `value`, case-insensitively, answering the
|
|
1443
|
+
* matching values of `id` paired with them. An FK on either side is followed to the PK it
|
|
1444
|
+
* points at. Without `value`, the first `limit` values.
|
|
1445
|
+
*/
|
|
1446
|
+
async function search(id, searchId, params, options = {}) {
|
|
1447
|
+
await transport.require("field.search", options);
|
|
1448
|
+
return transport.requestParsed(FieldSearchMatches, `/api/field/${id}/search/${searchId}`, {
|
|
1449
|
+
...options,
|
|
1450
|
+
query: {
|
|
1451
|
+
value: params.value,
|
|
1452
|
+
limit: params.limit
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* The value of `remappedId` on the one row where `id` equals `value`, as `[value, remapped]`,
|
|
1458
|
+
* or `null` when no row matches. `value` is parsed as a number for a numeric field.
|
|
1459
|
+
*/
|
|
1460
|
+
async function remapping(id, remappedId, params, options = {}) {
|
|
1461
|
+
await transport.require("field.remapping", options);
|
|
1462
|
+
return fetchOptionalParsed(transport, `/api/field/${id}/remapping/${remappedId}`, FieldRemappedValue, {
|
|
1463
|
+
...options,
|
|
1464
|
+
query: { value: params.value }
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
989
1467
|
/** Get the row count and the distinct-value count for a field. */
|
|
990
1468
|
async function summary(id, options = {}) {
|
|
991
1469
|
await transport.require("field.summary", options);
|
|
@@ -1004,23 +1482,13 @@ function fieldResource(transport) {
|
|
|
1004
1482
|
return {
|
|
1005
1483
|
get,
|
|
1006
1484
|
update,
|
|
1485
|
+
search,
|
|
1486
|
+
remapping,
|
|
1007
1487
|
summary,
|
|
1008
1488
|
values
|
|
1009
1489
|
};
|
|
1010
1490
|
}
|
|
1011
1491
|
//#endregion
|
|
1012
|
-
//#region ../client/src/resources/optional-parsed.ts
|
|
1013
|
-
const NO_CONTENT_STATUS = 204;
|
|
1014
|
-
async function fetchOptionalParsed(client, path, schema, options = {}) {
|
|
1015
|
-
const response = await client.requestRaw(path, {
|
|
1016
|
-
...options,
|
|
1017
|
-
method: "GET",
|
|
1018
|
-
expectContentType: "binary"
|
|
1019
|
-
});
|
|
1020
|
-
if (response.status === NO_CONTENT_STATUS) return null;
|
|
1021
|
-
return parseJsonOrPlain(await response.text(), response.headers.get("content-type"), schema, { source: response.url });
|
|
1022
|
-
}
|
|
1023
|
-
//#endregion
|
|
1024
1492
|
//#region ../client/src/resources/git-sync.ts
|
|
1025
1493
|
const SyncScopeCollection = Collection.pick({
|
|
1026
1494
|
id: true,
|
|
@@ -1141,6 +1609,19 @@ function gitSyncResource(transport) {
|
|
|
1141
1609
|
};
|
|
1142
1610
|
}
|
|
1143
1611
|
/**
|
|
1612
|
+
* Preview what exporting to `branch` would do against the live remote, without writing: whether
|
|
1613
|
+
* the remote has moved on, whether a merge would apply cleanly, which entities conflict, and what
|
|
1614
|
+
* a force push would discard. `branch` must be the one git-sync tracks; the server answers 409
|
|
1615
|
+
* otherwise.
|
|
1616
|
+
*/
|
|
1617
|
+
async function exportPreflight(params, options = {}) {
|
|
1618
|
+
await transport.require("gitSync.exportPreflight", options);
|
|
1619
|
+
return transport.requestParsed(SyncExportPreflight, "/api/ee/remote-sync/export-preflight", {
|
|
1620
|
+
...options,
|
|
1621
|
+
query: { branch: params.branch }
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1144
1625
|
* Export Metabase's current content to a branch the remote does not have yet. The endpoint
|
|
1145
1626
|
* queues a task and returns at once; pass `wait` to poll that task to a terminal status.
|
|
1146
1627
|
*/
|
|
@@ -1214,10 +1695,18 @@ function gitSyncResource(transport) {
|
|
|
1214
1695
|
throw error;
|
|
1215
1696
|
}
|
|
1216
1697
|
}
|
|
1217
|
-
/**
|
|
1698
|
+
/**
|
|
1699
|
+
* The branch git-sync tracks, or null when none is configured, the caller may not read it, or
|
|
1700
|
+
* the server has no remote-sync module.
|
|
1701
|
+
*/
|
|
1218
1702
|
async function branch(options = {}) {
|
|
1219
1703
|
await transport.require("gitSync.branch", options);
|
|
1220
|
-
|
|
1704
|
+
try {
|
|
1705
|
+
return await fetchOptionalParsed(transport, "/api/setting/remote-sync-branch", RemoteSyncSetting, options);
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
if (isRemoteUnreadable(error)) return null;
|
|
1708
|
+
throw error;
|
|
1709
|
+
}
|
|
1221
1710
|
}
|
|
1222
1711
|
/**
|
|
1223
1712
|
* Poll the current task until it reaches a terminal status. A server with no task at all
|
|
@@ -1241,6 +1730,7 @@ function gitSyncResource(transport) {
|
|
|
1241
1730
|
hasRemoteChanges,
|
|
1242
1731
|
import: importFromRemote,
|
|
1243
1732
|
export: exportToRemote,
|
|
1733
|
+
exportPreflight,
|
|
1244
1734
|
stash,
|
|
1245
1735
|
branches,
|
|
1246
1736
|
createBranch,
|
|
@@ -1252,6 +1742,84 @@ function gitSyncResource(transport) {
|
|
|
1252
1742
|
};
|
|
1253
1743
|
}
|
|
1254
1744
|
//#endregion
|
|
1745
|
+
//#region ../client/src/domain/glossary.ts
|
|
1746
|
+
const GlossaryCreator = z.object({
|
|
1747
|
+
id: z.number().int(),
|
|
1748
|
+
email: z.string(),
|
|
1749
|
+
first_name: z.string().nullable(),
|
|
1750
|
+
last_name: z.string().nullable()
|
|
1751
|
+
}).loose();
|
|
1752
|
+
const Glossary = z.object({
|
|
1753
|
+
id: z.number().int(),
|
|
1754
|
+
term: z.string(),
|
|
1755
|
+
definition: z.string(),
|
|
1756
|
+
creator_id: z.number().int(),
|
|
1757
|
+
creator: GlossaryCreator,
|
|
1758
|
+
created_at: z.string(),
|
|
1759
|
+
updated_at: z.string()
|
|
1760
|
+
}).loose();
|
|
1761
|
+
Glossary.pick({
|
|
1762
|
+
id: true,
|
|
1763
|
+
term: true,
|
|
1764
|
+
definition: true
|
|
1765
|
+
}).strip();
|
|
1766
|
+
z.object({
|
|
1767
|
+
term: z.string().min(1),
|
|
1768
|
+
definition: z.string().min(1)
|
|
1769
|
+
}).strict();
|
|
1770
|
+
//#endregion
|
|
1771
|
+
//#region ../client/src/resources/glossary.ts
|
|
1772
|
+
const GlossaryApiList = z.object({ data: z.array(Glossary) }).loose();
|
|
1773
|
+
function glossaryResource(transport) {
|
|
1774
|
+
/**
|
|
1775
|
+
* List glossary entries in term order. `search` keeps the entries whose term or definition
|
|
1776
|
+
* contains it, case-insensitively.
|
|
1777
|
+
*/
|
|
1778
|
+
async function list(params = {}, options = {}) {
|
|
1779
|
+
await transport.require("glossary.list", options);
|
|
1780
|
+
return {
|
|
1781
|
+
data: (await transport.requestParsed(GlossaryApiList, "/api/glossary", {
|
|
1782
|
+
...options,
|
|
1783
|
+
query: { search: params.search }
|
|
1784
|
+
})).data,
|
|
1785
|
+
total: null
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
/** Create a glossary entry, a term and its definition. Terms are unique. */
|
|
1789
|
+
async function create(params, options = {}) {
|
|
1790
|
+
await transport.require("glossary.create", options);
|
|
1791
|
+
return transport.requestParsed(Glossary, "/api/glossary", {
|
|
1792
|
+
...options,
|
|
1793
|
+
method: "POST",
|
|
1794
|
+
body: params
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
/** Replace the term and definition of a glossary entry by id. */
|
|
1798
|
+
async function update(id, params, options = {}) {
|
|
1799
|
+
await transport.require("glossary.update", options);
|
|
1800
|
+
return transport.requestParsed(Glossary, `/api/glossary/${id}`, {
|
|
1801
|
+
...options,
|
|
1802
|
+
method: "PUT",
|
|
1803
|
+
body: params
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
/** Delete a glossary entry by id. */
|
|
1807
|
+
async function remove(id, options = {}) {
|
|
1808
|
+
await transport.require("glossary.delete", options);
|
|
1809
|
+
await transport.requestRaw(`/api/glossary/${id}`, {
|
|
1810
|
+
...options,
|
|
1811
|
+
method: "DELETE",
|
|
1812
|
+
expectContentType: "binary"
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
list,
|
|
1817
|
+
create,
|
|
1818
|
+
update,
|
|
1819
|
+
delete: remove
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
//#endregion
|
|
1255
1823
|
//#region ../client/src/resources/library.ts
|
|
1256
1824
|
const LIBRARY_ROOT_PATH = "/api/ee/library/";
|
|
1257
1825
|
const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
|
|
@@ -1390,30 +1958,260 @@ function measureResource(transport) {
|
|
|
1390
1958
|
};
|
|
1391
1959
|
}
|
|
1392
1960
|
//#endregion
|
|
1393
|
-
//#region ../client/src/
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1961
|
+
//#region ../client/src/domain/metric.ts
|
|
1962
|
+
const ClauseOptions = z.object({}).loose();
|
|
1963
|
+
const MetricLeafType = z.enum(["metric", "measure"]);
|
|
1964
|
+
const MetricLeafRef = z.tuple([
|
|
1965
|
+
MetricLeafType,
|
|
1966
|
+
z.object({ "lib/uuid": z.string().min(1) }).strict(),
|
|
1967
|
+
z.number().int().positive()
|
|
1968
|
+
]);
|
|
1969
|
+
const MetricMathOperator = z.enum([
|
|
1970
|
+
"+",
|
|
1971
|
+
"-",
|
|
1972
|
+
"*",
|
|
1973
|
+
"/"
|
|
1974
|
+
]);
|
|
1975
|
+
const MetricMathExpression = z.lazy(() => z.union([
|
|
1976
|
+
MetricLeafRef,
|
|
1977
|
+
z.number(),
|
|
1978
|
+
z.tuple([
|
|
1979
|
+
MetricMathOperator,
|
|
1980
|
+
ClauseOptions,
|
|
1981
|
+
MetricMathExpression,
|
|
1982
|
+
MetricMathExpression
|
|
1983
|
+
]).rest(MetricMathExpression)
|
|
1984
|
+
]));
|
|
1985
|
+
const MetricBinning = z.discriminatedUnion("strategy", [
|
|
1986
|
+
z.object({ strategy: z.literal("default") }).strict(),
|
|
1987
|
+
z.object({
|
|
1988
|
+
strategy: z.literal("bin-width"),
|
|
1989
|
+
"bin-width": z.number().positive()
|
|
1990
|
+
}).strict(),
|
|
1991
|
+
z.object({
|
|
1992
|
+
strategy: z.literal("num-bins"),
|
|
1993
|
+
"num-bins": z.number().int().positive()
|
|
1994
|
+
}).strict()
|
|
1995
|
+
]);
|
|
1996
|
+
const MetricDimensionRefOptions = z.object({
|
|
1997
|
+
"lib/uuid": z.string().min(1).optional(),
|
|
1998
|
+
"display-name": z.string().min(1).nullable().optional(),
|
|
1999
|
+
"effective-type": FieldBaseType.nullable().optional(),
|
|
2000
|
+
"semantic-type": FieldSemanticType.nullable().optional(),
|
|
2001
|
+
"temporal-unit": TemporalUnit.nullable().optional(),
|
|
2002
|
+
binning: MetricBinning.nullable().optional()
|
|
2003
|
+
}).strict();
|
|
2004
|
+
const MetricDimensionRef = z.tuple([
|
|
2005
|
+
z.literal("dimension"),
|
|
2006
|
+
MetricDimensionRefOptions,
|
|
2007
|
+
z.string().min(1)
|
|
2008
|
+
]);
|
|
2009
|
+
const MetricFilterArgument = z.lazy(() => z.union([
|
|
2010
|
+
MetricDimensionRef,
|
|
2011
|
+
MetricFilterClause,
|
|
2012
|
+
z.string(),
|
|
2013
|
+
z.number(),
|
|
2014
|
+
z.boolean(),
|
|
2015
|
+
z.null()
|
|
2016
|
+
]));
|
|
2017
|
+
const MetricFilterClause = z.lazy(() => z.tuple([z.string().min(1), ClauseOptions]).rest(MetricFilterArgument));
|
|
2018
|
+
const MetricInstanceFilter = z.object({
|
|
2019
|
+
"lib/uuid": z.string().min(1),
|
|
2020
|
+
filter: MetricFilterClause
|
|
2021
|
+
}).strict();
|
|
2022
|
+
const MetricProjection = z.object({
|
|
2023
|
+
type: MetricLeafType,
|
|
2024
|
+
id: z.number().int().positive(),
|
|
2025
|
+
"lib/uuid": z.string().min(1),
|
|
2026
|
+
projection: z.array(MetricDimensionRef)
|
|
2027
|
+
}).strict();
|
|
2028
|
+
z.object({
|
|
2029
|
+
expression: MetricMathExpression,
|
|
2030
|
+
filters: z.array(MetricInstanceFilter).nullable().optional(),
|
|
2031
|
+
projections: z.array(MetricProjection).nullable().optional()
|
|
2032
|
+
}).strict();
|
|
2033
|
+
const MetricBreakoutColumn = z.object({
|
|
2034
|
+
name: z.string().optional(),
|
|
2035
|
+
display_name: z.string().optional(),
|
|
2036
|
+
base_type: FieldBaseType.optional(),
|
|
2037
|
+
effective_type: FieldBaseType.optional(),
|
|
2038
|
+
semantic_type: FieldSemanticType.nullable().optional()
|
|
2039
|
+
}).loose();
|
|
2040
|
+
const MetricBreakoutValues = z.object({
|
|
2041
|
+
values: z.array(z.unknown()),
|
|
2042
|
+
col: MetricBreakoutColumn
|
|
2043
|
+
}).loose();
|
|
2044
|
+
const MetricDimensionStatus = z.enum(["status/active", "status/orphaned"]);
|
|
2045
|
+
const MetricDimensionSource = z.object({
|
|
2046
|
+
type: z.literal("field"),
|
|
2047
|
+
"field-id": z.number().int().nullable()
|
|
2048
|
+
}).loose();
|
|
2049
|
+
const MetricDimensionGroup = z.object({
|
|
2050
|
+
id: z.string(),
|
|
2051
|
+
type: z.enum(["main", "connection"]),
|
|
2052
|
+
display_name: z.string()
|
|
2053
|
+
}).loose();
|
|
2054
|
+
const MetricDimension = z.object({
|
|
2055
|
+
id: z.string(),
|
|
2056
|
+
name: z.string().nullable(),
|
|
2057
|
+
display_name: z.string().nullable(),
|
|
2058
|
+
description: z.string().nullable().optional(),
|
|
2059
|
+
effective_type: FieldBaseType.nullable(),
|
|
2060
|
+
semantic_type: FieldSemanticType.nullable(),
|
|
2061
|
+
has_field_values: z.enum([
|
|
2062
|
+
"list",
|
|
2063
|
+
"search",
|
|
2064
|
+
"none"
|
|
2065
|
+
]).optional(),
|
|
2066
|
+
status: MetricDimensionStatus.optional(),
|
|
2067
|
+
status_message: z.string().optional(),
|
|
2068
|
+
sources: z.array(MetricDimensionSource).optional(),
|
|
2069
|
+
group: MetricDimensionGroup.optional(),
|
|
2070
|
+
dimension_interestingness: z.number().optional(),
|
|
2071
|
+
default_temporal_unit: TemporalUnit.optional(),
|
|
2072
|
+
default: z.boolean().nullable().optional()
|
|
2073
|
+
}).loose();
|
|
2074
|
+
MetricDimension.pick({
|
|
2075
|
+
id: true,
|
|
2076
|
+
name: true,
|
|
2077
|
+
display_name: true,
|
|
2078
|
+
description: true,
|
|
2079
|
+
effective_type: true,
|
|
2080
|
+
semantic_type: true,
|
|
2081
|
+
status: true,
|
|
2082
|
+
group: true,
|
|
2083
|
+
default: true
|
|
2084
|
+
}).strip();
|
|
2085
|
+
const MetricMappingTarget = z.tuple([z.string(), ClauseOptions]).rest(z.unknown());
|
|
2086
|
+
const MetricAddableDimension = MetricDimension.extend({ mapping_target: MetricMappingTarget });
|
|
2087
|
+
const MetricAddableGroup = z.object({
|
|
2088
|
+
group: MetricDimensionGroup.nullable(),
|
|
2089
|
+
dimensions: z.array(MetricAddableDimension)
|
|
2090
|
+
}).loose();
|
|
2091
|
+
const MetricDimensionListing = z.object({
|
|
2092
|
+
added: z.array(MetricDimension),
|
|
2093
|
+
addable: z.array(MetricAddableGroup)
|
|
2094
|
+
}).loose();
|
|
2095
|
+
//#endregion
|
|
2096
|
+
//#region ../client/src/resources/metric.ts
|
|
2097
|
+
function metricResource(transport) {
|
|
2098
|
+
/**
|
|
2099
|
+
* Run a metric definition and return the query result envelope: one metric or measure, or an
|
|
2100
|
+
* arithmetic expression over several, each leaf filtered and projected on its own `lib/uuid`.
|
|
2101
|
+
*/
|
|
2102
|
+
async function query(definition, options = {}) {
|
|
2103
|
+
await transport.require("metric.query", options);
|
|
2104
|
+
return transport.requestParsed(CardQueryResult, "/api/metric/dataset", {
|
|
2105
|
+
...options,
|
|
2106
|
+
method: "POST",
|
|
2107
|
+
body: { definition }
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
/**
|
|
2111
|
+
* Fetch the distinct values of a definition's breakout dimension, with that column's metadata.
|
|
2112
|
+
* Takes the same definition `query` does.
|
|
2113
|
+
*/
|
|
2114
|
+
async function breakoutValues(definition, options = {}) {
|
|
2115
|
+
await transport.require("metric.breakoutValues", options);
|
|
2116
|
+
return transport.requestParsed(MetricBreakoutValues, "/api/metric/breakout-values", {
|
|
2117
|
+
...options,
|
|
2118
|
+
method: "POST",
|
|
2119
|
+
body: { definition }
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
/**
|
|
2123
|
+
* List a metric's curated dimensions and, under `with-addable`, the columns still available to
|
|
2124
|
+
* add, grouped by source table. `query` filters both by a name substring.
|
|
2125
|
+
*/
|
|
2126
|
+
async function dimensions(id, params = {}, options = {}) {
|
|
2127
|
+
await transport.require("metric.dimensions", options);
|
|
2128
|
+
return transport.requestParsed(MetricDimensionListing, `/api/metric/${id}/dimension`, {
|
|
2129
|
+
...options,
|
|
2130
|
+
query: {
|
|
2131
|
+
query: params.query,
|
|
2132
|
+
"with-addable": params["with-addable"],
|
|
2133
|
+
"include-orphaned": params["include-orphaned"]
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
}
|
|
2137
|
+
return {
|
|
2138
|
+
query,
|
|
2139
|
+
breakoutValues,
|
|
2140
|
+
dimensions
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
//#endregion
|
|
2144
|
+
//#region ../client/src/domain/moderation-review.ts
|
|
2145
|
+
const ModeratedItemType = z.enum(["card", "dashboard"]);
|
|
2146
|
+
const ModerationStatus = z.enum(["verified"]);
|
|
2147
|
+
const ModerationReview = z.object({
|
|
2148
|
+
id: z.number().int(),
|
|
2149
|
+
moderated_item_id: z.number().int(),
|
|
2150
|
+
moderated_item_type: ModeratedItemType,
|
|
2151
|
+
moderator_id: z.number().int(),
|
|
2152
|
+
status: ModerationStatus.nullable(),
|
|
2153
|
+
text: z.string().nullable(),
|
|
2154
|
+
most_recent: z.boolean(),
|
|
2155
|
+
created_at: z.string(),
|
|
2156
|
+
updated_at: z.string()
|
|
2157
|
+
}).loose();
|
|
2158
|
+
ModerationReview.pick({
|
|
2159
|
+
id: true,
|
|
2160
|
+
moderated_item_id: true,
|
|
2161
|
+
moderated_item_type: true,
|
|
2162
|
+
status: true,
|
|
2163
|
+
text: true,
|
|
2164
|
+
most_recent: true
|
|
2165
|
+
}).strip();
|
|
2166
|
+
z.object({
|
|
2167
|
+
moderated_item_id: z.number().int().positive(),
|
|
2168
|
+
moderated_item_type: ModeratedItemType,
|
|
2169
|
+
status: ModerationStatus.nullable().optional(),
|
|
2170
|
+
text: z.string().nullable().optional()
|
|
2171
|
+
}).strict();
|
|
2172
|
+
//#endregion
|
|
2173
|
+
//#region ../client/src/resources/moderation-review.ts
|
|
2174
|
+
function moderationReviewResource(transport) {
|
|
2175
|
+
/**
|
|
2176
|
+
* Create a moderation review on a card or dashboard. `status: "verified"` marks the item
|
|
2177
|
+
* verified, `null` or an absent status records a note that leaves it unverified. The new review
|
|
2178
|
+
* becomes the item's most recent one; the server keeps the ten newest per item. Admins only.
|
|
2179
|
+
*/
|
|
2180
|
+
async function create(params, options = {}) {
|
|
2181
|
+
await transport.require("moderationReview.create", options);
|
|
2182
|
+
return transport.requestParsed(ModerationReview, "/api/moderation-review", {
|
|
2183
|
+
...options,
|
|
2184
|
+
method: "POST",
|
|
2185
|
+
body: params
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
return { create };
|
|
2189
|
+
}
|
|
2190
|
+
//#endregion
|
|
2191
|
+
//#region ../client/src/resources/notification.ts
|
|
2192
|
+
const NotificationApiList = z.array(Notification);
|
|
2193
|
+
function assertCardAlert(notification) {
|
|
2194
|
+
if (notification.payload_type !== "notification/card") throw new ConfigError(`notification ${notification.id} is a ${notification.payload_type}, not a question alert — this operation accepts card alerts only`);
|
|
2195
|
+
return notification;
|
|
2196
|
+
}
|
|
2197
|
+
function mergeAlertUpdate(current, patch) {
|
|
2198
|
+
return Notification.parse({
|
|
2199
|
+
...current,
|
|
2200
|
+
...patch,
|
|
2201
|
+
id: current.id,
|
|
2202
|
+
payload: patch.payload === void 0 ? current.payload : mergePayload(current, patch.payload)
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
function mergePayload(current, patch) {
|
|
2206
|
+
if (current.payload === null) throw new ConfigError(`alert ${current.id} has lost its card payload — it can be archived, but not patched`);
|
|
2207
|
+
return NotificationCardPayload.parse({
|
|
2208
|
+
...current.payload,
|
|
2209
|
+
...patch
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
function notificationResource(transport) {
|
|
2213
|
+
/**
|
|
2214
|
+
* List question alerts, optionally narrowed by the card they watch, their creator, or a
|
|
1417
2215
|
* recipient. `/api/notification` also serves Metabase's internal system-event notifications, so
|
|
1418
2216
|
* the request pins the card payload type.
|
|
1419
2217
|
*/
|
|
@@ -1485,6 +2283,72 @@ function notificationResource(transport) {
|
|
|
1485
2283
|
};
|
|
1486
2284
|
}
|
|
1487
2285
|
//#endregion
|
|
2286
|
+
//#region ../client/src/domain/permission.ts
|
|
2287
|
+
const ViewDataPermission = z.enum([
|
|
2288
|
+
"unrestricted",
|
|
2289
|
+
"legacy-no-self-service",
|
|
2290
|
+
"blocked",
|
|
2291
|
+
"sandboxed",
|
|
2292
|
+
"impersonated"
|
|
2293
|
+
]);
|
|
2294
|
+
const CreateQueriesPermission = z.enum([
|
|
2295
|
+
"query-builder-and-native",
|
|
2296
|
+
"query-builder",
|
|
2297
|
+
"no"
|
|
2298
|
+
]);
|
|
2299
|
+
const DownloadPermission = z.enum(["full", "limited"]);
|
|
2300
|
+
const DataModelPermission = z.literal("all");
|
|
2301
|
+
const YesNoPermission = z.enum(["yes", "no"]);
|
|
2302
|
+
function granular(value) {
|
|
2303
|
+
const perTable = z.record(z.string(), value);
|
|
2304
|
+
const perSchema = z.record(z.string(), z.union([value, perTable]));
|
|
2305
|
+
return z.union([value, perSchema]);
|
|
2306
|
+
}
|
|
2307
|
+
const DatabasePermissions = z.object({
|
|
2308
|
+
"view-data": granular(ViewDataPermission).optional(),
|
|
2309
|
+
"create-queries": granular(CreateQueriesPermission).optional(),
|
|
2310
|
+
download: z.object({ schemas: granular(DownloadPermission) }).loose().optional(),
|
|
2311
|
+
"data-model": z.object({ schemas: granular(DataModelPermission) }).loose().optional(),
|
|
2312
|
+
details: YesNoPermission.optional(),
|
|
2313
|
+
transforms: YesNoPermission.optional()
|
|
2314
|
+
}).loose();
|
|
2315
|
+
const PermissionsGraph = z.object({
|
|
2316
|
+
revision: z.number().int().nonnegative(),
|
|
2317
|
+
groups: z.record(z.string(), z.record(z.string(), DatabasePermissions))
|
|
2318
|
+
}).loose();
|
|
2319
|
+
//#endregion
|
|
2320
|
+
//#region ../client/src/resources/permission.ts
|
|
2321
|
+
function permissionResource(transport) {
|
|
2322
|
+
/**
|
|
2323
|
+
* Get the data permissions of every group on every database, keyed by group id then database
|
|
2324
|
+
* id. Admin only. One read of the whole `data_permissions` table, so prefer `databaseGraph` when
|
|
2325
|
+
* one database is the question.
|
|
2326
|
+
*/
|
|
2327
|
+
async function graph(options = {}) {
|
|
2328
|
+
await transport.require("permission.graph", options);
|
|
2329
|
+
return transport.requestParsed(PermissionsGraph, "/api/permissions/graph", { ...options });
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Get the data permissions of every group on one database. Admin only. The read is filtered to
|
|
2333
|
+
* that database, so this is the cheapest way to learn which groups can query a table: look the
|
|
2334
|
+
* group up under the database and read `view-data` and `create-queries` down to the table id.
|
|
2335
|
+
*/
|
|
2336
|
+
async function databaseGraph(id, options = {}) {
|
|
2337
|
+
await transport.require("permission.databaseGraph", options);
|
|
2338
|
+
return transport.requestParsed(PermissionsGraph, `/api/permissions/graph/db/${id}`, { ...options });
|
|
2339
|
+
}
|
|
2340
|
+
/** Get the data permissions of one group on every database. Admin only. */
|
|
2341
|
+
async function groupGraph(id, options = {}) {
|
|
2342
|
+
await transport.require("permission.groupGraph", options);
|
|
2343
|
+
return transport.requestParsed(PermissionsGraph, `/api/permissions/graph/group/${id}`, { ...options });
|
|
2344
|
+
}
|
|
2345
|
+
return {
|
|
2346
|
+
graph,
|
|
2347
|
+
databaseGraph,
|
|
2348
|
+
groupGraph
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
//#endregion
|
|
1488
2352
|
//#region ../client/src/resources/pulse.ts
|
|
1489
2353
|
const PulseApiList = z.array(Pulse);
|
|
1490
2354
|
function mergePulseUpdate(current, patch) {
|
|
@@ -1550,6 +2414,284 @@ function pulseResource(transport) {
|
|
|
1550
2414
|
};
|
|
1551
2415
|
}
|
|
1552
2416
|
//#endregion
|
|
2417
|
+
//#region ../client/src/domain/replacement.ts
|
|
2418
|
+
const ReplacementSourceType = z.enum(["card", "table"]);
|
|
2419
|
+
const ReplacementEntityType = z.enum([...ReplacementSourceType.options, "transform"]);
|
|
2420
|
+
const ReplacementRunStatus = z.enum([
|
|
2421
|
+
"pending",
|
|
2422
|
+
"started",
|
|
2423
|
+
"succeeded",
|
|
2424
|
+
"failed",
|
|
2425
|
+
"canceled",
|
|
2426
|
+
"timeout"
|
|
2427
|
+
]);
|
|
2428
|
+
const ReplacementRun = z.object({
|
|
2429
|
+
id: z.number().int(),
|
|
2430
|
+
status: ReplacementRunStatus,
|
|
2431
|
+
is_active: z.literal(true).nullable(),
|
|
2432
|
+
source_entity_type: ReplacementEntityType,
|
|
2433
|
+
source_entity_id: z.number().int(),
|
|
2434
|
+
target_entity_type: ReplacementEntityType,
|
|
2435
|
+
target_entity_id: z.number().int(),
|
|
2436
|
+
progress: z.number().min(0).max(1).nullable(),
|
|
2437
|
+
message: z.string().nullable(),
|
|
2438
|
+
user_id: z.number().int().nullable(),
|
|
2439
|
+
start_time: z.string(),
|
|
2440
|
+
end_time: z.string().nullable()
|
|
2441
|
+
}).loose();
|
|
2442
|
+
ReplacementRun.pick({
|
|
2443
|
+
id: true,
|
|
2444
|
+
status: true,
|
|
2445
|
+
source_entity_type: true,
|
|
2446
|
+
source_entity_id: true,
|
|
2447
|
+
target_entity_type: true,
|
|
2448
|
+
target_entity_id: true,
|
|
2449
|
+
progress: true,
|
|
2450
|
+
message: true,
|
|
2451
|
+
start_time: true,
|
|
2452
|
+
end_time: true
|
|
2453
|
+
}).strip();
|
|
2454
|
+
const ReplacementColumn = z.object({
|
|
2455
|
+
id: z.number().int().nullable(),
|
|
2456
|
+
name: z.string(),
|
|
2457
|
+
display_name: z.string(),
|
|
2458
|
+
base_type: FieldBaseType.nullable(),
|
|
2459
|
+
effective_type: FieldBaseType.nullable(),
|
|
2460
|
+
semantic_type: FieldSemanticType.nullable()
|
|
2461
|
+
});
|
|
2462
|
+
const ReplacementColumnError = z.enum([
|
|
2463
|
+
"column-type-mismatch",
|
|
2464
|
+
"missing-primary-key",
|
|
2465
|
+
"missing-foreign-key",
|
|
2466
|
+
"foreign-key-mismatch"
|
|
2467
|
+
]);
|
|
2468
|
+
const ReplacementColumnMatched = z.object({
|
|
2469
|
+
source: ReplacementColumn,
|
|
2470
|
+
target: ReplacementColumn,
|
|
2471
|
+
errors: z.array(ReplacementColumnError).optional()
|
|
2472
|
+
}).strict();
|
|
2473
|
+
const ReplacementColumnMissingOnTarget = z.object({ source: ReplacementColumn }).strict();
|
|
2474
|
+
const ReplacementColumnMissingOnSource = z.object({ target: ReplacementColumn }).strict();
|
|
2475
|
+
const ReplacementColumnMapping = z.union([
|
|
2476
|
+
ReplacementColumnMatched,
|
|
2477
|
+
ReplacementColumnMissingOnTarget,
|
|
2478
|
+
ReplacementColumnMissingOnSource
|
|
2479
|
+
]);
|
|
2480
|
+
const ReplacementError = z.enum([
|
|
2481
|
+
"cycle-detected",
|
|
2482
|
+
"database-mismatch",
|
|
2483
|
+
"incompatible-implicit-joins",
|
|
2484
|
+
"affects-gtap-policies"
|
|
2485
|
+
]);
|
|
2486
|
+
const ReplacementCheck = z.object({
|
|
2487
|
+
success: z.boolean(),
|
|
2488
|
+
errors: z.array(ReplacementError).optional(),
|
|
2489
|
+
column_mappings: z.array(ReplacementColumnMapping).optional()
|
|
2490
|
+
});
|
|
2491
|
+
z.object({
|
|
2492
|
+
source_entity_id: z.number().int().positive(),
|
|
2493
|
+
source_entity_type: ReplacementSourceType,
|
|
2494
|
+
target_entity_id: z.number().int().positive(),
|
|
2495
|
+
target_entity_type: ReplacementSourceType
|
|
2496
|
+
}).strict();
|
|
2497
|
+
z.object({
|
|
2498
|
+
card_id: z.number().int().positive(),
|
|
2499
|
+
transform_name: z.string(),
|
|
2500
|
+
transform_target: TransformTarget,
|
|
2501
|
+
target_collection_id: z.number().int().positive().nullable().optional(),
|
|
2502
|
+
transform_tag_ids: z.array(z.number().int().positive()).nullable().optional()
|
|
2503
|
+
}).strict();
|
|
2504
|
+
const ReplacementRunStarted = z.object({ run_id: z.number().int().positive() });
|
|
2505
|
+
//#endregion
|
|
2506
|
+
//#region ../client/src/resources/replacement.ts
|
|
2507
|
+
const ReplacementApiRunList = z.array(ReplacementRun);
|
|
2508
|
+
const CancelRunResponse = z.object({ success: z.literal(true) });
|
|
2509
|
+
function replacementResource(transport) {
|
|
2510
|
+
/**
|
|
2511
|
+
* Check whether every usage of a source entity could be rewritten to read a target entity
|
|
2512
|
+
* instead: the two must share a database, the target must not depend on the source, every source
|
|
2513
|
+
* column must exist on the target with a compatible type, and a table source must not be joined
|
|
2514
|
+
* implicitly or sandboxed. Admins only.
|
|
2515
|
+
*/
|
|
2516
|
+
async function checkReplaceSource(params, options = {}) {
|
|
2517
|
+
await transport.require("replacement.checkReplaceSource", options);
|
|
2518
|
+
return transport.requestParsed(ReplacementCheck, "/api/ee/replacement/check-replace-source", {
|
|
2519
|
+
...options,
|
|
2520
|
+
method: "POST",
|
|
2521
|
+
body: params
|
|
2522
|
+
});
|
|
2523
|
+
}
|
|
2524
|
+
/**
|
|
2525
|
+
* Rewrite every usage of a source entity to read a target entity, in the background. Runs the
|
|
2526
|
+
* same check as `checkReplaceSource` first and refuses with a 400 when it fails, and with a 409
|
|
2527
|
+
* while another replacement is running. Admins only.
|
|
2528
|
+
*/
|
|
2529
|
+
async function replaceSource(params, options = {}) {
|
|
2530
|
+
await transport.require("replacement.replaceSource", options);
|
|
2531
|
+
return transport.requestParsed(ReplacementRunStarted, "/api/ee/replacement/replace-source", {
|
|
2532
|
+
...options,
|
|
2533
|
+
method: "POST",
|
|
2534
|
+
body: params
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Create a transform from a model's query, run it, and rewrite every usage of the model to read
|
|
2539
|
+
* the transform's output table, in the background; the model becomes a saved question. A failed
|
|
2540
|
+
* transform run leaves the model as it was; a failed rewrite keeps the transform and its table
|
|
2541
|
+
* as well, since other queries may already read them. Refuses with a 409 while another
|
|
2542
|
+
* replacement is running. Admins only.
|
|
2543
|
+
*/
|
|
2544
|
+
async function replaceModelWithTransform(params, options = {}) {
|
|
2545
|
+
await transport.require("replacement.replaceModelWithTransform", options);
|
|
2546
|
+
return transport.requestParsed(ReplacementRunStarted, "/api/ee/replacement/replace-model-with-transform", {
|
|
2547
|
+
...options,
|
|
2548
|
+
method: "POST",
|
|
2549
|
+
body: params
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2552
|
+
/**
|
|
2553
|
+
* List replacement runs, newest first. `is-active: true` keeps only the run in progress,
|
|
2554
|
+
* `false` only the ended ones. Admins only.
|
|
2555
|
+
*/
|
|
2556
|
+
async function listRuns(params = {}, options = {}) {
|
|
2557
|
+
await transport.require("replacement.listRuns", options);
|
|
2558
|
+
return {
|
|
2559
|
+
data: await transport.requestParsed(ReplacementApiRunList, "/api/ee/replacement/runs", {
|
|
2560
|
+
...options,
|
|
2561
|
+
query: { "is-active": params["is-active"] }
|
|
2562
|
+
}),
|
|
2563
|
+
total: null
|
|
2564
|
+
};
|
|
2565
|
+
}
|
|
2566
|
+
/** Get one replacement run by id, with its status and progress. Admins only. */
|
|
2567
|
+
async function getRun(id, options = {}) {
|
|
2568
|
+
await transport.require("replacement.getRun", options);
|
|
2569
|
+
return transport.requestParsed(ReplacementRun, `/api/ee/replacement/runs/${id}`, { ...options });
|
|
2570
|
+
}
|
|
2571
|
+
/** Cancel the replacement in progress. Refuses with a 409 once the run has ended. Admins only. */
|
|
2572
|
+
async function cancelRun(id, options = {}) {
|
|
2573
|
+
await transport.require("replacement.cancelRun", options);
|
|
2574
|
+
await transport.requestParsed(CancelRunResponse, `/api/ee/replacement/runs/${id}/cancel`, {
|
|
2575
|
+
...options,
|
|
2576
|
+
method: "POST"
|
|
2577
|
+
});
|
|
2578
|
+
}
|
|
2579
|
+
return {
|
|
2580
|
+
checkReplaceSource,
|
|
2581
|
+
replaceSource,
|
|
2582
|
+
replaceModelWithTransform,
|
|
2583
|
+
listRuns,
|
|
2584
|
+
getRun,
|
|
2585
|
+
cancelRun
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
//#endregion
|
|
2589
|
+
//#region ../client/src/domain/revision.ts
|
|
2590
|
+
const RevisionEntity = z.enum([
|
|
2591
|
+
"card",
|
|
2592
|
+
"dashboard",
|
|
2593
|
+
"document",
|
|
2594
|
+
"measure",
|
|
2595
|
+
"segment",
|
|
2596
|
+
"transform"
|
|
2597
|
+
]);
|
|
2598
|
+
const RevisionUser = z.object({
|
|
2599
|
+
id: z.number().int(),
|
|
2600
|
+
first_name: z.string().nullable(),
|
|
2601
|
+
last_name: z.string().nullable(),
|
|
2602
|
+
common_name: z.string()
|
|
2603
|
+
}).loose();
|
|
2604
|
+
const Revision = z.object({
|
|
2605
|
+
id: z.number().int(),
|
|
2606
|
+
timestamp: z.string(),
|
|
2607
|
+
is_creation: z.boolean(),
|
|
2608
|
+
is_reversion: z.boolean(),
|
|
2609
|
+
most_recent: z.boolean(),
|
|
2610
|
+
diff: z.object({}).loose().nullable(),
|
|
2611
|
+
description: z.string(),
|
|
2612
|
+
has_multiple_changes: z.boolean(),
|
|
2613
|
+
user: RevisionUser
|
|
2614
|
+
}).loose();
|
|
2615
|
+
Revision.pick({
|
|
2616
|
+
id: true,
|
|
2617
|
+
timestamp: true,
|
|
2618
|
+
is_creation: true,
|
|
2619
|
+
is_reversion: true,
|
|
2620
|
+
description: true,
|
|
2621
|
+
user: true
|
|
2622
|
+
}).strip();
|
|
2623
|
+
const RevisionRow = z.object({
|
|
2624
|
+
id: z.number().int(),
|
|
2625
|
+
model: z.string(),
|
|
2626
|
+
model_id: z.number().int(),
|
|
2627
|
+
user_id: z.number().int(),
|
|
2628
|
+
object: z.object({}).loose(),
|
|
2629
|
+
timestamp: z.string(),
|
|
2630
|
+
is_creation: z.boolean(),
|
|
2631
|
+
is_reversion: z.boolean(),
|
|
2632
|
+
most_recent: z.boolean()
|
|
2633
|
+
}).loose();
|
|
2634
|
+
z.object({
|
|
2635
|
+
entity: RevisionEntity,
|
|
2636
|
+
id: z.number().int().positive(),
|
|
2637
|
+
revision_id: z.number().int().positive()
|
|
2638
|
+
}).strict();
|
|
2639
|
+
const RevisionReverted = z.object({
|
|
2640
|
+
outcome: z.literal("reverted"),
|
|
2641
|
+
revision: Revision
|
|
2642
|
+
});
|
|
2643
|
+
const RevisionUnchanged = z.object({
|
|
2644
|
+
outcome: z.literal("unchanged"),
|
|
2645
|
+
revision: RevisionRow
|
|
2646
|
+
});
|
|
2647
|
+
z.discriminatedUnion("outcome", [RevisionReverted, RevisionUnchanged]);
|
|
2648
|
+
//#endregion
|
|
2649
|
+
//#region ../client/src/resources/revision.ts
|
|
2650
|
+
const RevisionApiList = z.array(Revision);
|
|
2651
|
+
const RevisionApiRevert = z.union([Revision.transform((revision) => ({
|
|
2652
|
+
outcome: "reverted",
|
|
2653
|
+
revision
|
|
2654
|
+
})), RevisionRow.transform((revision) => ({
|
|
2655
|
+
outcome: "unchanged",
|
|
2656
|
+
revision
|
|
2657
|
+
}))]);
|
|
2658
|
+
const ENTITY_FEATURES = {
|
|
2659
|
+
measure: "measures",
|
|
2660
|
+
transform: "transforms"
|
|
2661
|
+
};
|
|
2662
|
+
function entityFeatures(entity) {
|
|
2663
|
+
const feature = ENTITY_FEATURES[entity];
|
|
2664
|
+
return feature === void 0 ? [] : [feature];
|
|
2665
|
+
}
|
|
2666
|
+
function revisionResource(transport) {
|
|
2667
|
+
/** List the revisions of an entity the caller may read, newest first, each with its diff. */
|
|
2668
|
+
async function list(entity, id, options = {}) {
|
|
2669
|
+
await transport.require("revision.list", options);
|
|
2670
|
+
await transport.requireFeatures(entityFeatures(entity), options);
|
|
2671
|
+
return {
|
|
2672
|
+
data: await transport.requestParsed(RevisionApiList, `/api/revision/${entity}/${id}`, { ...options }),
|
|
2673
|
+
total: null
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
/**
|
|
2677
|
+
* Revert an entity to one of its prior revisions. Needs write access to the entity, and for a
|
|
2678
|
+
* card the permission to run the query being restored.
|
|
2679
|
+
*/
|
|
2680
|
+
async function revert(params, options = {}) {
|
|
2681
|
+
await transport.require("revision.revert", options);
|
|
2682
|
+
await transport.requireFeatures(entityFeatures(params.entity), options);
|
|
2683
|
+
return transport.requestParsed(RevisionApiRevert, "/api/revision/revert", {
|
|
2684
|
+
...options,
|
|
2685
|
+
method: "POST",
|
|
2686
|
+
body: params
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
return {
|
|
2690
|
+
list,
|
|
2691
|
+
revert
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
//#endregion
|
|
1553
2695
|
//#region ../client/src/resources/search.ts
|
|
1554
2696
|
const SearchApiResponse = z.object({
|
|
1555
2697
|
data: z.array(SearchResult),
|
|
@@ -1559,8 +2701,10 @@ function searchResource(transport) {
|
|
|
1559
2701
|
/**
|
|
1560
2702
|
* Search over the instance's content, ranked against `q`. `models` narrows which kinds of entity
|
|
1561
2703
|
* may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
|
|
1562
|
-
* items on one database, `verified` to verified content,
|
|
1563
|
-
*
|
|
2704
|
+
* items on one database, `verified` to verified content, `collection` to one collection and its
|
|
2705
|
+
* descendants, `created_by` to items created by any of those users, `search_native_query` also
|
|
2706
|
+
* matches the text of native queries, `include_metadata` attaches each card's `result_metadata`,
|
|
2707
|
+
* and `limit`/`offset` are the window the server applies before ranking hydration.
|
|
1564
2708
|
*/
|
|
1565
2709
|
async function query(params = {}, options = {}) {
|
|
1566
2710
|
await transport.require("search.query", options);
|
|
@@ -1573,7 +2717,11 @@ function searchResource(transport) {
|
|
|
1573
2717
|
limit: params.limit,
|
|
1574
2718
|
offset: params.offset,
|
|
1575
2719
|
table_db_id: params.table_db_id,
|
|
1576
|
-
verified: params.verified
|
|
2720
|
+
verified: params.verified,
|
|
2721
|
+
collection: params.collection,
|
|
2722
|
+
created_by: params.created_by,
|
|
2723
|
+
search_native_query: params.search_native_query,
|
|
2724
|
+
include_metadata: params.include_metadata
|
|
1577
2725
|
}
|
|
1578
2726
|
});
|
|
1579
2727
|
return {
|
|
@@ -1755,16 +2903,52 @@ function snippetResource(transport) {
|
|
|
1755
2903
|
//#endregion
|
|
1756
2904
|
//#region ../client/src/resources/table.ts
|
|
1757
2905
|
const TableApiList = z.array(Table);
|
|
2906
|
+
const TableApiFks = z.array(TableForeignKey);
|
|
2907
|
+
const SyncSchemaResponse = z.object({ status: z.literal("ok") });
|
|
2908
|
+
const RescanValuesResponse = z.object({ status: z.literal("success") });
|
|
2909
|
+
const BulkEditResponse = z.object({});
|
|
2910
|
+
const BULK_EDIT_PATH = "/api/data-studio/table/edit";
|
|
2911
|
+
const LIST_PARAM_FEATURES = [
|
|
2912
|
+
["can-query", "tableListAccessFilters"],
|
|
2913
|
+
["can-write", "tableListAccessFilters"],
|
|
2914
|
+
["include-transform-targets", "tableListTransformTargets"],
|
|
2915
|
+
["unused-only", "tableUnusedFilter"]
|
|
2916
|
+
];
|
|
2917
|
+
function listParamFeatures(params) {
|
|
2918
|
+
return LIST_PARAM_FEATURES.filter(([param]) => params[param] !== void 0).map(([, feature]) => feature);
|
|
2919
|
+
}
|
|
1758
2920
|
const UPLOAD_UPDATE_PATHS = {
|
|
1759
2921
|
append: "append-csv",
|
|
1760
2922
|
replace: "replace-csv"
|
|
1761
2923
|
};
|
|
1762
2924
|
function tableResource(transport) {
|
|
1763
|
-
/**
|
|
1764
|
-
|
|
2925
|
+
/**
|
|
2926
|
+
* List every table the caller can see, across all databases. `term` matches names and display
|
|
2927
|
+
* names; `can-query` and `can-write` keep only the tables the caller may query or edit the
|
|
2928
|
+
* metadata of; `include-transform-targets` adds tables a transform writes to; `unused-only` keeps
|
|
2929
|
+
* tables nothing depends on.
|
|
2930
|
+
*/
|
|
2931
|
+
async function list(params = {}, options = {}) {
|
|
1765
2932
|
await transport.require("table.list", options);
|
|
2933
|
+
await transport.requireFeatures(listParamFeatures(params), options);
|
|
2934
|
+
await requireDataLayer(params["data-layer"], options);
|
|
1766
2935
|
return {
|
|
1767
|
-
data: await transport.requestParsed(TableApiList, "/api/table", {
|
|
2936
|
+
data: await transport.requestParsed(TableApiList, "/api/table", {
|
|
2937
|
+
...options,
|
|
2938
|
+
query: {
|
|
2939
|
+
term: params.term,
|
|
2940
|
+
"visibility-type": params["visibility-type"],
|
|
2941
|
+
"data-layer": params["data-layer"],
|
|
2942
|
+
"data-source": params["data-source"],
|
|
2943
|
+
"owner-user-id": params["owner-user-id"],
|
|
2944
|
+
"owner-email": params["owner-email"],
|
|
2945
|
+
"orphan-only": params["orphan-only"],
|
|
2946
|
+
"unused-only": params["unused-only"],
|
|
2947
|
+
"can-query": params["can-query"],
|
|
2948
|
+
"can-write": params["can-write"],
|
|
2949
|
+
"include-transform-targets": params["include-transform-targets"]
|
|
2950
|
+
}
|
|
2951
|
+
}),
|
|
1768
2952
|
total: null
|
|
1769
2953
|
};
|
|
1770
2954
|
}
|
|
@@ -1776,17 +2960,72 @@ function tableResource(transport) {
|
|
|
1776
2960
|
/** Update a table by id, patching only the fields the body carries. */
|
|
1777
2961
|
async function update(id, params, options = {}) {
|
|
1778
2962
|
await transport.require("table.update", options);
|
|
2963
|
+
await requireDataLayer(params.data_layer, options);
|
|
1779
2964
|
return transport.requestParsed(Table, `/api/table/${id}`, {
|
|
1780
2965
|
...options,
|
|
1781
2966
|
method: "PUT",
|
|
1782
2967
|
body: params
|
|
1783
2968
|
});
|
|
1784
2969
|
}
|
|
2970
|
+
async function requireDataLayer(value, options) {
|
|
2971
|
+
if (value === null || value === void 0) return;
|
|
2972
|
+
if (TableDataLayerTier.safeParse(value).success) {
|
|
2973
|
+
await transport.requireFeatures(["tableDataLayerTiers"], options);
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
const { features } = await transport.server(options);
|
|
2977
|
+
if (features.tableDataLayerTiers) throw new ConfigError(`data_layer "${value}" is a medallion name; this server names a table's layer ${TableDataLayerTier.options.join(", ")}`);
|
|
2978
|
+
}
|
|
1785
2979
|
/** Get a table by id with its fields hydrated — the metadata the query builder runs on. */
|
|
1786
2980
|
async function queryMetadata(id, options = {}) {
|
|
1787
2981
|
await transport.require("table.queryMetadata", options);
|
|
1788
2982
|
return transport.requestParsed(TableQueryMetadata, `/api/table/${id}/query_metadata`, { ...options });
|
|
1789
2983
|
}
|
|
2984
|
+
/**
|
|
2985
|
+
* Get every foreign key whose destination is a field of this table. A table with no active
|
|
2986
|
+
* fields answers no content, which is the same empty list.
|
|
2987
|
+
*/
|
|
2988
|
+
async function fks(id, options = {}) {
|
|
2989
|
+
await transport.require("table.fks", options);
|
|
2990
|
+
return {
|
|
2991
|
+
data: await fetchOptionalParsed(transport, `/api/table/${id}/fks`, TableApiFks, { ...options }) ?? [],
|
|
2992
|
+
total: null
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* Trigger a manual update of this table's schema metadata. The sync runs after the call returns;
|
|
2997
|
+
* a warehouse the server cannot connect to is a 422.
|
|
2998
|
+
*/
|
|
2999
|
+
async function syncSchema(id, options = {}) {
|
|
3000
|
+
await transport.require("table.syncSchema", options);
|
|
3001
|
+
await transport.requestParsed(SyncSchemaResponse, `/api/table/${id}/sync_schema`, {
|
|
3002
|
+
...options,
|
|
3003
|
+
method: "POST"
|
|
3004
|
+
});
|
|
3005
|
+
}
|
|
3006
|
+
/**
|
|
3007
|
+
* Trigger an update of the field values of every eligible field of this table. The scan runs
|
|
3008
|
+
* after the call returns.
|
|
3009
|
+
*/
|
|
3010
|
+
async function rescanValues(id, options = {}) {
|
|
3011
|
+
await transport.require("table.rescanValues", options);
|
|
3012
|
+
await transport.requestParsed(RescanValuesResponse, `/api/table/${id}/rescan_values`, {
|
|
3013
|
+
...options,
|
|
3014
|
+
method: "POST"
|
|
3015
|
+
});
|
|
3016
|
+
}
|
|
3017
|
+
/**
|
|
3018
|
+
* Set the same metadata on every table the selectors pick out. A table leaving the `hidden` data
|
|
3019
|
+
* layer is re-synced after the call returns.
|
|
3020
|
+
*/
|
|
3021
|
+
async function bulkEdit(params, options = {}) {
|
|
3022
|
+
await transport.require("table.bulkEdit", options);
|
|
3023
|
+
await transport.requestParsed(BulkEditResponse, BULK_EDIT_PATH, {
|
|
3024
|
+
...options,
|
|
3025
|
+
method: "POST",
|
|
3026
|
+
body: params
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
1790
3029
|
async function updateFromCsv(id, action, file, options) {
|
|
1791
3030
|
await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
|
|
1792
3031
|
...options,
|
|
@@ -1824,6 +3063,10 @@ function tableResource(transport) {
|
|
|
1824
3063
|
get,
|
|
1825
3064
|
update,
|
|
1826
3065
|
queryMetadata,
|
|
3066
|
+
fks,
|
|
3067
|
+
syncSchema,
|
|
3068
|
+
rescanValues,
|
|
3069
|
+
bulkEdit,
|
|
1827
3070
|
appendCsv,
|
|
1828
3071
|
replaceCsv
|
|
1829
3072
|
};
|
|
@@ -1969,6 +3212,235 @@ function timelineResource(transport) {
|
|
|
1969
3212
|
};
|
|
1970
3213
|
}
|
|
1971
3214
|
//#endregion
|
|
3215
|
+
//#region ../client/src/domain/transform-dag-run.ts
|
|
3216
|
+
const TransformMemberRun = TransformRun.extend({
|
|
3217
|
+
job_run_id: z.number().int().nullable(),
|
|
3218
|
+
dag_run_id: z.number().int().nullable()
|
|
3219
|
+
});
|
|
3220
|
+
TransformMemberRun.pick({
|
|
3221
|
+
id: true,
|
|
3222
|
+
transform_id: true,
|
|
3223
|
+
dag_run_id: true,
|
|
3224
|
+
status: true,
|
|
3225
|
+
run_method: true,
|
|
3226
|
+
start_time: true,
|
|
3227
|
+
end_time: true,
|
|
3228
|
+
message: true
|
|
3229
|
+
}).strip();
|
|
3230
|
+
//#endregion
|
|
3231
|
+
//#region ../client/src/resources/transform-dag-run.ts
|
|
3232
|
+
const TransformMemberRunList = z.array(TransformMemberRun);
|
|
3233
|
+
function transformDagRunResource(transport) {
|
|
3234
|
+
/**
|
|
3235
|
+
* List the transform runs a DAG run coordinated so far. A member run is inserted when its
|
|
3236
|
+
* transform starts, so the list grows while the DAG run is in progress.
|
|
3237
|
+
*/
|
|
3238
|
+
async function transformRuns(runId, options = {}) {
|
|
3239
|
+
await transport.require("transformDagRun.transformRuns", options);
|
|
3240
|
+
return {
|
|
3241
|
+
data: await transport.requestParsed(TransformMemberRunList, `/api/transform-dag-run/${runId}/transform-runs`, { ...options }),
|
|
3242
|
+
total: null
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
/** Cancel an in-progress DAG run and request cancellation of its still-running transforms. */
|
|
3246
|
+
async function cancel(runId, options = {}) {
|
|
3247
|
+
await transport.require("transformDagRun.cancel", options);
|
|
3248
|
+
await transport.requestRaw(`/api/transform-dag-run/${runId}/cancel`, {
|
|
3249
|
+
...options,
|
|
3250
|
+
method: "POST",
|
|
3251
|
+
expectContentType: "binary"
|
|
3252
|
+
});
|
|
3253
|
+
}
|
|
3254
|
+
return {
|
|
3255
|
+
transformRuns,
|
|
3256
|
+
cancel
|
|
3257
|
+
};
|
|
3258
|
+
}
|
|
3259
|
+
//#endregion
|
|
3260
|
+
//#region ../client/src/domain/transform-inspector.ts
|
|
3261
|
+
const InspectorFieldStats = z.object({
|
|
3262
|
+
distinct_count: z.number().int().optional(),
|
|
3263
|
+
nil_percent: z.number().optional(),
|
|
3264
|
+
min: z.number().optional(),
|
|
3265
|
+
max: z.number().optional(),
|
|
3266
|
+
avg: z.number().optional(),
|
|
3267
|
+
q1: z.number().optional(),
|
|
3268
|
+
q3: z.number().optional(),
|
|
3269
|
+
earliest: z.string().optional(),
|
|
3270
|
+
latest: z.string().optional()
|
|
3271
|
+
}).loose();
|
|
3272
|
+
const InspectorField = z.object({
|
|
3273
|
+
id: z.number().int(),
|
|
3274
|
+
name: z.string(),
|
|
3275
|
+
display_name: z.string().nullable().optional(),
|
|
3276
|
+
base_type: z.string(),
|
|
3277
|
+
semantic_type: z.string().nullable().optional(),
|
|
3278
|
+
stats: InspectorFieldStats.nullable().optional()
|
|
3279
|
+
}).loose();
|
|
3280
|
+
const InspectorTable = z.object({
|
|
3281
|
+
table_id: z.number().int(),
|
|
3282
|
+
table_name: z.string(),
|
|
3283
|
+
schema: z.string().nullable().optional(),
|
|
3284
|
+
db_id: z.number().int(),
|
|
3285
|
+
column_count: z.number().int(),
|
|
3286
|
+
fields: z.array(InspectorField)
|
|
3287
|
+
}).loose();
|
|
3288
|
+
const LensComplexityLevel = z.enum([
|
|
3289
|
+
"fast",
|
|
3290
|
+
"slow",
|
|
3291
|
+
"very-slow"
|
|
3292
|
+
]);
|
|
3293
|
+
const LensComplexity = z.object({
|
|
3294
|
+
level: LensComplexityLevel,
|
|
3295
|
+
score: z.number().int().optional()
|
|
3296
|
+
}).loose();
|
|
3297
|
+
const LensMetadata = z.object({
|
|
3298
|
+
id: z.string(),
|
|
3299
|
+
display_name: z.string(),
|
|
3300
|
+
description: z.string().nullable().optional(),
|
|
3301
|
+
complexity: LensComplexity.optional()
|
|
3302
|
+
}).loose();
|
|
3303
|
+
const TransformInspectionStatus = z.enum(["not-run", "ready"]);
|
|
3304
|
+
const TransformInspection = z.object({
|
|
3305
|
+
name: z.string(),
|
|
3306
|
+
description: z.string().nullable().optional(),
|
|
3307
|
+
status: TransformInspectionStatus,
|
|
3308
|
+
sources: z.array(InspectorTable),
|
|
3309
|
+
target: InspectorTable.nullable().optional(),
|
|
3310
|
+
visited_fields: z.object({ all: z.array(z.number().int()).optional() }).loose().nullable().optional(),
|
|
3311
|
+
available_lenses: z.array(LensMetadata)
|
|
3312
|
+
}).loose();
|
|
3313
|
+
const LensCardDisplay = z.enum([
|
|
3314
|
+
"bar",
|
|
3315
|
+
"row",
|
|
3316
|
+
"line",
|
|
3317
|
+
"area",
|
|
3318
|
+
"pie",
|
|
3319
|
+
"scalar",
|
|
3320
|
+
"gauge",
|
|
3321
|
+
"progress",
|
|
3322
|
+
"table",
|
|
3323
|
+
"hidden"
|
|
3324
|
+
]);
|
|
3325
|
+
const LensJoinMetadata = z.object({
|
|
3326
|
+
join_step: z.number().int().optional(),
|
|
3327
|
+
join_alias: z.string().optional(),
|
|
3328
|
+
join_strategy: z.string().optional()
|
|
3329
|
+
}).loose();
|
|
3330
|
+
const LensCardMetadata = LensJoinMetadata.extend({
|
|
3331
|
+
dedup_key: z.array(z.unknown()).optional(),
|
|
3332
|
+
depends_on_cards: z.array(z.string()).optional(),
|
|
3333
|
+
group_id: z.string().optional(),
|
|
3334
|
+
group_role: z.enum(["input", "output"]).optional(),
|
|
3335
|
+
group_order: z.number().int().optional(),
|
|
3336
|
+
card_type: z.string().optional()
|
|
3337
|
+
});
|
|
3338
|
+
const LensCard = z.object({
|
|
3339
|
+
id: z.string(),
|
|
3340
|
+
section_id: z.string().nullable().optional(),
|
|
3341
|
+
title: z.string(),
|
|
3342
|
+
display: LensCardDisplay,
|
|
3343
|
+
dataset_query: DatasetQuery,
|
|
3344
|
+
metadata: LensCardMetadata.optional()
|
|
3345
|
+
}).loose();
|
|
3346
|
+
const LensSection = z.object({
|
|
3347
|
+
id: z.string(),
|
|
3348
|
+
title: z.string(),
|
|
3349
|
+
description: z.string().nullable().optional(),
|
|
3350
|
+
layout: z.enum(["flat", "comparison"]).optional()
|
|
3351
|
+
}).loose();
|
|
3352
|
+
const LensHighlight = z.object({
|
|
3353
|
+
label: z.string(),
|
|
3354
|
+
value: z.unknown().optional(),
|
|
3355
|
+
card_id: z.string().optional()
|
|
3356
|
+
}).loose();
|
|
3357
|
+
const LensSummary = z.object({
|
|
3358
|
+
text: z.string().nullable().optional(),
|
|
3359
|
+
highlights: z.array(LensHighlight).optional(),
|
|
3360
|
+
alerts: z.array(z.object({}).loose()).optional()
|
|
3361
|
+
}).loose();
|
|
3362
|
+
const LensTriggerCondition = z.object({ name: z.string() }).loose();
|
|
3363
|
+
const LensAlertTrigger = z.object({
|
|
3364
|
+
id: z.string(),
|
|
3365
|
+
condition: LensTriggerCondition,
|
|
3366
|
+
severity: z.enum([
|
|
3367
|
+
"info",
|
|
3368
|
+
"warning",
|
|
3369
|
+
"error"
|
|
3370
|
+
]),
|
|
3371
|
+
message: z.string(),
|
|
3372
|
+
metadata: LensJoinMetadata.optional()
|
|
3373
|
+
}).loose();
|
|
3374
|
+
/** The parameters a drill lens takes; `join_step` scopes a join lens to one join. */
|
|
3375
|
+
const LensParams = z.object({ join_step: z.number().int().optional() });
|
|
3376
|
+
const LensDrillTrigger = z.object({
|
|
3377
|
+
lens_id: z.string(),
|
|
3378
|
+
condition: LensTriggerCondition,
|
|
3379
|
+
params: LensParams.loose().optional(),
|
|
3380
|
+
reason: z.string().optional(),
|
|
3381
|
+
metadata: LensJoinMetadata.optional()
|
|
3382
|
+
}).loose();
|
|
3383
|
+
const TransformLens = z.object({
|
|
3384
|
+
id: z.string(),
|
|
3385
|
+
display_name: z.string(),
|
|
3386
|
+
complexity: LensComplexity.optional(),
|
|
3387
|
+
summary: LensSummary.optional(),
|
|
3388
|
+
sections: z.array(LensSection),
|
|
3389
|
+
cards: z.array(LensCard),
|
|
3390
|
+
drill_lenses: z.array(LensMetadata).optional(),
|
|
3391
|
+
alert_triggers: z.array(LensAlertTrigger).optional(),
|
|
3392
|
+
drill_lens_triggers: z.array(LensDrillTrigger).optional()
|
|
3393
|
+
}).loose();
|
|
3394
|
+
z.object({
|
|
3395
|
+
query: DatasetQuery,
|
|
3396
|
+
lens_params: LensParams.nullable().optional()
|
|
3397
|
+
}).strict();
|
|
3398
|
+
//#endregion
|
|
3399
|
+
//#region ../client/src/resources/transform-inspector.ts
|
|
3400
|
+
function lensPath(id, lensId) {
|
|
3401
|
+
return `/api/ee/transforms/${id}/inspect/${encodeURIComponent(lensId)}`;
|
|
3402
|
+
}
|
|
3403
|
+
function transformInspectorResource(transport) {
|
|
3404
|
+
/**
|
|
3405
|
+
* Discover what the inspector can show for a transform: its source and target tables with field
|
|
3406
|
+
* statistics, the fields its query touches, and the lenses available on it.
|
|
3407
|
+
*/
|
|
3408
|
+
async function discover(id, options = {}) {
|
|
3409
|
+
await transport.require("transformInspector.discover", options);
|
|
3410
|
+
return transport.requestParsed(TransformInspection, `/api/ee/transforms/${id}/inspect`, { ...options });
|
|
3411
|
+
}
|
|
3412
|
+
/**
|
|
3413
|
+
* Open one lens on a transform: its sections, the cards with the queries that fill them, and
|
|
3414
|
+
* the alert and drill-lens triggers to evaluate against the card results. A drill lens takes
|
|
3415
|
+
* the `params` its trigger emitted.
|
|
3416
|
+
*/
|
|
3417
|
+
async function lens(id, lensId, params = {}, options = {}) {
|
|
3418
|
+
await transport.require("transformInspector.lens", options);
|
|
3419
|
+
return transport.requestParsed(TransformLens, lensPath(id, lensId), {
|
|
3420
|
+
...options,
|
|
3421
|
+
query: { join_step: params.join_step }
|
|
3422
|
+
});
|
|
3423
|
+
}
|
|
3424
|
+
/**
|
|
3425
|
+
* Run a lens card's query in the context of the lens, so the execution is attributed to the
|
|
3426
|
+
* inspector. The body is the card's `dataset_query`, and the same `lens_params` the lens was
|
|
3427
|
+
* opened with.
|
|
3428
|
+
*/
|
|
3429
|
+
async function query(id, lensId, params, options = {}) {
|
|
3430
|
+
await transport.require("transformInspector.query", options);
|
|
3431
|
+
return transport.requestParsed(CardQueryResult, `${lensPath(id, lensId)}/query`, {
|
|
3432
|
+
...options,
|
|
3433
|
+
method: "POST",
|
|
3434
|
+
body: params
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
return {
|
|
3438
|
+
discover,
|
|
3439
|
+
lens,
|
|
3440
|
+
query
|
|
3441
|
+
};
|
|
3442
|
+
}
|
|
3443
|
+
//#endregion
|
|
1972
3444
|
//#region ../client/src/resources/transform-job.ts
|
|
1973
3445
|
function transformJobResource(transport) {
|
|
1974
3446
|
/** List every transform job the caller can see. */
|
|
@@ -2061,6 +3533,96 @@ function transformJobResource(transport) {
|
|
|
2061
3533
|
};
|
|
2062
3534
|
}
|
|
2063
3535
|
//#endregion
|
|
3536
|
+
//#region ../client/src/domain/transform-python.ts
|
|
3537
|
+
const PythonLibrary = z.object({
|
|
3538
|
+
path: z.string(),
|
|
3539
|
+
source: z.string().nullable(),
|
|
3540
|
+
created_at: z.string(),
|
|
3541
|
+
updated_at: z.string()
|
|
3542
|
+
}).loose();
|
|
3543
|
+
z.object({ source: z.string() }).strict();
|
|
3544
|
+
const TEST_RUN_ROW_LIMIT = {
|
|
3545
|
+
min: 2,
|
|
3546
|
+
max: 100
|
|
3547
|
+
};
|
|
3548
|
+
const TestRunRowLimit = z.number().int().min(TEST_RUN_ROW_LIMIT.min).max(TEST_RUN_ROW_LIMIT.max);
|
|
3549
|
+
z.object({
|
|
3550
|
+
code: z.string(),
|
|
3551
|
+
source_tables: z.array(TransformSourceTableEntry).min(1),
|
|
3552
|
+
output_row_limit: TestRunRowLimit.optional(),
|
|
3553
|
+
per_input_row_limit: TestRunRowLimit.optional()
|
|
3554
|
+
}).strict();
|
|
3555
|
+
const PythonTestRunOutput = z.object({
|
|
3556
|
+
cols: z.array(z.object({ name: z.string() }).loose()),
|
|
3557
|
+
rows: z.array(z.unknown())
|
|
3558
|
+
});
|
|
3559
|
+
const PythonTestRunError = z.object({ message: z.string() }).loose();
|
|
3560
|
+
const PythonTestRunSucceeded = z.object({
|
|
3561
|
+
outcome: z.literal("succeeded"),
|
|
3562
|
+
logs: z.string(),
|
|
3563
|
+
output: PythonTestRunOutput
|
|
3564
|
+
});
|
|
3565
|
+
const PythonTestRunFailed = z.object({
|
|
3566
|
+
outcome: z.literal("failed"),
|
|
3567
|
+
logs: z.string(),
|
|
3568
|
+
error: PythonTestRunError
|
|
3569
|
+
});
|
|
3570
|
+
z.discriminatedUnion("outcome", [PythonTestRunSucceeded, PythonTestRunFailed]);
|
|
3571
|
+
//#endregion
|
|
3572
|
+
//#region ../client/src/resources/transform-python.ts
|
|
3573
|
+
const PythonApiTestRun = z.union([z.object({
|
|
3574
|
+
logs: z.string(),
|
|
3575
|
+
output: PythonTestRunOutput
|
|
3576
|
+
}).transform(({ logs, output }) => ({
|
|
3577
|
+
outcome: "succeeded",
|
|
3578
|
+
logs,
|
|
3579
|
+
output
|
|
3580
|
+
})), z.object({
|
|
3581
|
+
logs: z.string(),
|
|
3582
|
+
error: PythonTestRunError
|
|
3583
|
+
}).transform(({ logs, error }) => ({
|
|
3584
|
+
outcome: "failed",
|
|
3585
|
+
logs,
|
|
3586
|
+
error
|
|
3587
|
+
}))]);
|
|
3588
|
+
function libraryPath(path) {
|
|
3589
|
+
return `/api/ee/transforms-python/library/${encodeURIComponent(path)}`;
|
|
3590
|
+
}
|
|
3591
|
+
function transformPythonResource(transport) {
|
|
3592
|
+
/** Get the Python library at a path, the user module every Python transform can import. */
|
|
3593
|
+
async function getLibrary(path, options = {}) {
|
|
3594
|
+
await transport.require("transformPython.getLibrary", options);
|
|
3595
|
+
return transport.requestParsed(PythonLibrary, libraryPath(path), { ...options });
|
|
3596
|
+
}
|
|
3597
|
+
/** Replace the source of the Python library at a path, creating the library when none exists. */
|
|
3598
|
+
async function updateLibrary(path, params, options = {}) {
|
|
3599
|
+
await transport.require("transformPython.updateLibrary", options);
|
|
3600
|
+
return transport.requestParsed(PythonLibrary, libraryPath(path), {
|
|
3601
|
+
...options,
|
|
3602
|
+
method: "PUT",
|
|
3603
|
+
body: params
|
|
3604
|
+
});
|
|
3605
|
+
}
|
|
3606
|
+
/**
|
|
3607
|
+
* Evaluate an ad-hoc Python transform on a sample of its source tables, without a target table.
|
|
3608
|
+
* Meant for early feedback on short runs: input, output and time limits apply, and the sample
|
|
3609
|
+
* sizes are capped at 100 rows.
|
|
3610
|
+
*/
|
|
3611
|
+
async function testRun(params, options = {}) {
|
|
3612
|
+
await transport.require("transformPython.testRun", options);
|
|
3613
|
+
return transport.requestParsed(PythonApiTestRun, "/api/ee/transforms-python/test-run", {
|
|
3614
|
+
...options,
|
|
3615
|
+
method: "POST",
|
|
3616
|
+
body: params
|
|
3617
|
+
});
|
|
3618
|
+
}
|
|
3619
|
+
return {
|
|
3620
|
+
getLibrary,
|
|
3621
|
+
updateLibrary,
|
|
3622
|
+
testRun
|
|
3623
|
+
};
|
|
3624
|
+
}
|
|
3625
|
+
//#endregion
|
|
2064
3626
|
//#region ../client/src/resources/transform.ts
|
|
2065
3627
|
function transformListSchema(features) {
|
|
2066
3628
|
return z.array(transformRowSchema(features));
|
|
@@ -2069,6 +3631,7 @@ const TransformRunKickoff = z.object({
|
|
|
2069
3631
|
message: z.string(),
|
|
2070
3632
|
run_id: z.number().int().positive().nullable()
|
|
2071
3633
|
});
|
|
3634
|
+
const TransformDagTransformList = z.array(TransformDagTransform);
|
|
2072
3635
|
function transformResource(transport) {
|
|
2073
3636
|
async function requestTransformList(path, opts) {
|
|
2074
3637
|
const { features } = await transport.server(opts);
|
|
@@ -2159,6 +3722,67 @@ function transformResource(transport) {
|
|
|
2159
3722
|
});
|
|
2160
3723
|
}
|
|
2161
3724
|
/**
|
|
3725
|
+
* Walk the unified run history, newest first by default: every row is a root run — a job run, a
|
|
3726
|
+
* DAG reprocess run, or a standalone transform run — and never a member run of a job or DAG.
|
|
3727
|
+
*/
|
|
3728
|
+
async function* runSummaryPages(params = {}, options = {}) {
|
|
3729
|
+
await transport.require("transform.runSummaryPages", options);
|
|
3730
|
+
yield* paginatePages(transport, "/api/transform/runs", TransformRunSummary, {
|
|
3731
|
+
query: {
|
|
3732
|
+
types: params.types,
|
|
3733
|
+
statuses: params.statuses,
|
|
3734
|
+
"run-methods": params["run-methods"],
|
|
3735
|
+
"start-time": params["start-time"],
|
|
3736
|
+
"end-time": params["end-time"],
|
|
3737
|
+
"transform-ids": params["transform-ids"],
|
|
3738
|
+
"sort-column": params["sort-column"],
|
|
3739
|
+
"sort-direction": params["sort-direction"]
|
|
3740
|
+
},
|
|
3741
|
+
...options.offset !== void 0 && { offset: options.offset },
|
|
3742
|
+
...options.max !== void 0 && { max: options.max },
|
|
3743
|
+
...options.pageSize !== void 0 && { pageSize: options.pageSize },
|
|
3744
|
+
...options.signal !== void 0 && { signal: options.signal }
|
|
3745
|
+
});
|
|
3746
|
+
}
|
|
3747
|
+
/**
|
|
3748
|
+
* Reset the stored checkpoint of an incremental transform, so its next run reprocesses the whole
|
|
3749
|
+
* source rather than the rows past the last checkpoint.
|
|
3750
|
+
*/
|
|
3751
|
+
async function resetCheckpoint(id, options = {}) {
|
|
3752
|
+
await transport.require("transform.resetCheckpoint", options);
|
|
3753
|
+
await transport.requestRaw(`/api/transform/${id}/reset-checkpoint`, {
|
|
3754
|
+
...options,
|
|
3755
|
+
method: "POST",
|
|
3756
|
+
expectContentType: "binary"
|
|
3757
|
+
});
|
|
3758
|
+
}
|
|
3759
|
+
/**
|
|
3760
|
+
* Start a DAG reprocess run seeded at a transform: the transform plus, by `direction`, every
|
|
3761
|
+
* transform it transitively depends on or every transform that transitively depends on it. The
|
|
3762
|
+
* server answers at once with the run's id, or null when it ran nothing because a DAG run for
|
|
3763
|
+
* this transform is already in progress or the closure is empty. Progress is read off
|
|
3764
|
+
* `runSummaryPages` with `types: ["dag"]`, and the member runs off `transformDagRun.transformRuns`.
|
|
3765
|
+
*/
|
|
3766
|
+
async function runDag(id, params, options = {}) {
|
|
3767
|
+
await transport.require("transform.runDag", options);
|
|
3768
|
+
return transport.requestParsed(TransformDagRunResult, `/api/transform/${id}/run-dag`, {
|
|
3769
|
+
...options,
|
|
3770
|
+
method: "POST",
|
|
3771
|
+
body: { direction: params.direction }
|
|
3772
|
+
});
|
|
3773
|
+
}
|
|
3774
|
+
/** Preview the transforms a DAG reprocess seeded at a transform would run, in execution order. */
|
|
3775
|
+
async function dagTransforms(id, params, options = {}) {
|
|
3776
|
+
await transport.require("transform.dagTransforms", options);
|
|
3777
|
+
return {
|
|
3778
|
+
data: await transport.requestParsed(TransformDagTransformList, `/api/transform/${id}/dag-transforms`, {
|
|
3779
|
+
...options,
|
|
3780
|
+
query: { direction: params.direction }
|
|
3781
|
+
}),
|
|
3782
|
+
total: null
|
|
3783
|
+
};
|
|
3784
|
+
}
|
|
3785
|
+
/**
|
|
2162
3786
|
* Start a run of a transform by id. The server queues the run and answers at once; `wait` polls
|
|
2163
3787
|
* it to a terminal status, and `syncTarget` follows that with the output table's registration.
|
|
2164
3788
|
* A server that answers no run id started nothing, and there is then nothing to poll.
|
|
@@ -2215,6 +3839,10 @@ function transformResource(transport) {
|
|
|
2215
3839
|
cancel,
|
|
2216
3840
|
getRun,
|
|
2217
3841
|
runPages,
|
|
3842
|
+
runSummaryPages,
|
|
3843
|
+
resetCheckpoint,
|
|
3844
|
+
runDag,
|
|
3845
|
+
dagTransforms,
|
|
2218
3846
|
run
|
|
2219
3847
|
};
|
|
2220
3848
|
}
|
|
@@ -2265,6 +3893,82 @@ function transformTagResource(transport) {
|
|
|
2265
3893
|
};
|
|
2266
3894
|
}
|
|
2267
3895
|
//#endregion
|
|
3896
|
+
//#region ../client/src/resources/transform-test.ts
|
|
3897
|
+
const TransformTestApiList = z.array(TransformTest);
|
|
3898
|
+
function transformTestResource(transport) {
|
|
3899
|
+
/** List the transform tests, optionally only those of one transform. */
|
|
3900
|
+
async function list(params = {}, options = {}) {
|
|
3901
|
+
await transport.require("transformTest.list", options);
|
|
3902
|
+
return {
|
|
3903
|
+
data: await transport.requestParsed(TransformTestApiList, "/api/ee/transform-test", {
|
|
3904
|
+
...options,
|
|
3905
|
+
query: { "transform-id": params["transform-id"] }
|
|
3906
|
+
}),
|
|
3907
|
+
total: null
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3910
|
+
/** Get a transform test by id. */
|
|
3911
|
+
async function get(id, options = {}) {
|
|
3912
|
+
await transport.require("transformTest.get", options);
|
|
3913
|
+
return transport.requestParsed(TransformTest, `/api/ee/transform-test/${id}`, { ...options });
|
|
3914
|
+
}
|
|
3915
|
+
/**
|
|
3916
|
+
* Create a transform test. The server validates the inputs and expectations against the
|
|
3917
|
+
* transform before saving, and refuses with an `HttpError` whose `errorCode` is a
|
|
3918
|
+
* `TransformTestRefusalCode` when they cannot run.
|
|
3919
|
+
*/
|
|
3920
|
+
async function create(params, options = {}) {
|
|
3921
|
+
await transport.require("transformTest.create", options);
|
|
3922
|
+
return transport.requestParsed(TransformTest, "/api/ee/transform-test", {
|
|
3923
|
+
...options,
|
|
3924
|
+
method: "POST",
|
|
3925
|
+
body: params
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3928
|
+
/**
|
|
3929
|
+
* Update a transform test by id, leaving omitted fields unchanged. A body that touches the
|
|
3930
|
+
* transform, inputs or expectations is validated as on create, with the same refusal.
|
|
3931
|
+
*/
|
|
3932
|
+
async function update(id, params, options = {}) {
|
|
3933
|
+
await transport.require("transformTest.update", options);
|
|
3934
|
+
return transport.requestParsed(TransformTest, `/api/ee/transform-test/${id}`, {
|
|
3935
|
+
...options,
|
|
3936
|
+
method: "PUT",
|
|
3937
|
+
body: params
|
|
3938
|
+
});
|
|
3939
|
+
}
|
|
3940
|
+
/** Delete a transform test by id. */
|
|
3941
|
+
async function remove(id, options = {}) {
|
|
3942
|
+
await transport.require("transformTest.delete", options);
|
|
3943
|
+
await transport.requestRaw(`/api/ee/transform-test/${id}`, {
|
|
3944
|
+
...options,
|
|
3945
|
+
method: "DELETE",
|
|
3946
|
+
expectContentType: "binary"
|
|
3947
|
+
});
|
|
3948
|
+
}
|
|
3949
|
+
/**
|
|
3950
|
+
* Run a transform test by id. A result means the run happened: `status` is `passed` or `failed`
|
|
3951
|
+
* and every expectation reports what it found, one that could not be evaluated as its own
|
|
3952
|
+
* `error`. An `HttpError` whose `errorCode` is a `TransformTestRefusalCode` means the run was
|
|
3953
|
+
* refused and nothing meaningful ran.
|
|
3954
|
+
*/
|
|
3955
|
+
async function run(id, options = {}) {
|
|
3956
|
+
await transport.require("transformTest.run", options);
|
|
3957
|
+
return transport.requestParsed(TransformTestRunResult, `/api/ee/transform-test/${id}/run`, {
|
|
3958
|
+
...options,
|
|
3959
|
+
method: "POST"
|
|
3960
|
+
});
|
|
3961
|
+
}
|
|
3962
|
+
return {
|
|
3963
|
+
list,
|
|
3964
|
+
get,
|
|
3965
|
+
create,
|
|
3966
|
+
update,
|
|
3967
|
+
delete: remove,
|
|
3968
|
+
run
|
|
3969
|
+
};
|
|
3970
|
+
}
|
|
3971
|
+
//#endregion
|
|
2268
3972
|
//#region ../client/src/resources/upload.ts
|
|
2269
3973
|
const UPLOAD_TABLE_ID_HEADER = "metabase-table-id";
|
|
2270
3974
|
function uploadResource(transport) {
|
|
@@ -2345,14 +4049,22 @@ function createClient(config, options) {
|
|
|
2345
4049
|
dashboard: dashboardResource(transport),
|
|
2346
4050
|
database: databaseResource(transport),
|
|
2347
4051
|
dataset: datasetResource(transport),
|
|
4052
|
+
dependency: dependencyResource(transport),
|
|
2348
4053
|
document: documentResource(transport),
|
|
2349
4054
|
eidTranslation: eidTranslationResource(transport),
|
|
4055
|
+
erd: erdResource(transport),
|
|
2350
4056
|
field: fieldResource(transport),
|
|
2351
4057
|
gitSync: gitSyncResource(transport),
|
|
4058
|
+
glossary: glossaryResource(transport),
|
|
2352
4059
|
library: libraryResource(transport),
|
|
2353
4060
|
measure: measureResource(transport),
|
|
4061
|
+
metric: metricResource(transport),
|
|
4062
|
+
moderationReview: moderationReviewResource(transport),
|
|
2354
4063
|
notification: notificationResource(transport),
|
|
4064
|
+
permission: permissionResource(transport),
|
|
2355
4065
|
pulse: pulseResource(transport),
|
|
4066
|
+
replacement: replacementResource(transport),
|
|
4067
|
+
revision: revisionResource(transport),
|
|
2356
4068
|
search: searchResource(transport),
|
|
2357
4069
|
segment: segmentResource(transport),
|
|
2358
4070
|
setting: settingResource(transport),
|
|
@@ -2362,8 +4074,12 @@ function createClient(config, options) {
|
|
|
2362
4074
|
timeline: timelineResource(transport),
|
|
2363
4075
|
timelineEvent: timelineEventResource(transport),
|
|
2364
4076
|
transform: transformResource(transport),
|
|
4077
|
+
transformDagRun: transformDagRunResource(transport),
|
|
4078
|
+
transformInspector: transformInspectorResource(transport),
|
|
2365
4079
|
transformJob: transformJobResource(transport),
|
|
4080
|
+
transformPython: transformPythonResource(transport),
|
|
2366
4081
|
transformTag: transformTagResource(transport),
|
|
4082
|
+
transformTest: transformTestResource(transport),
|
|
2367
4083
|
upload: uploadResource(transport),
|
|
2368
4084
|
user: userResource(transport),
|
|
2369
4085
|
server: transport.server,
|