@mistriwork/mistri 1.0.0-rc.12 → 1.0.0-rc.13
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/README.md +4 -3
- package/dist/client/assets/LayoutBuilder-MPzkVU2e.js.map +1 -1
- package/dist/client/assets/index-D2dHI6hR.js.map +1 -1
- package/dist/client/assets/shell-TreN_uLs.js.map +1 -1
- package/dist/docs/access-model.md +1 -1
- package/dist/docs/build-and-deploy.md +0 -1
- package/dist/docs/cli.md +1 -1
- package/dist/docs/glossary.md +3 -3
- package/dist/docs/query.md +9 -21
- package/dist/docs/status.md +3 -3
- package/dist/embed/react/chunks/LayoutBuilder-Cbxa_wve.js.map +1 -1
- package/dist/embed/react/chunks/app-0UZ1Re1k.js.map +1 -1
- package/dist/embed/react/chunks/page-Bx4o1kpQ.js.map +1 -1
- package/dist/embed/react/chunks/palette-Bb7Lf6eo.js.map +1 -1
- package/dist/embed/react/chunks/shell-DZRACiB9.js.map +1 -1
- package/dist/embed/react/chunks/write-BQO4CFc9.js.map +1 -1
- package/dist/embed/react/index.js +1 -1
- package/dist/server/build/dockerfile.js +1 -1
- package/dist/server/cli/usage.js +2 -2
- package/dist/ui/index.js +2 -2
- package/dist/ui/page.js +2 -2
- package/dist/ui/{shared-N4Ej8yRD.js → shared-1PD7TOTJ.js} +5 -5
- package/dist/ui/{shared-N4Ej8yRD.js.map → shared-1PD7TOTJ.js.map} +1 -1
- package/dist/ui/{shared-D5m86-4o.js → shared-1gMnOu9J.js} +6 -6
- package/dist/ui/{shared-D5m86-4o.js.map → shared-1gMnOu9J.js.map} +1 -1
- package/dist/ui/{shared-Ctaj8mR2.js → shared-5RQMi4BR.js} +3 -3
- package/dist/ui/{shared-Ctaj8mR2.js.map → shared-5RQMi4BR.js.map} +1 -1
- package/dist/ui/{shared-DpLeIATZ.js → shared-B-BUF9fx.js} +2 -2
- package/dist/ui/{shared-DpLeIATZ.js.map → shared-B-BUF9fx.js.map} +1 -1
- package/dist/ui/{shared-DWYnjItP.js → shared-B-MhiPIN.js} +9 -9
- package/dist/ui/{shared-DWYnjItP.js.map → shared-B-MhiPIN.js.map} +1 -1
- package/dist/ui/{shared-0fNuhSbG.js → shared-B07qIMlE.js} +5 -5
- package/dist/ui/{shared-0fNuhSbG.js.map → shared-B07qIMlE.js.map} +1 -1
- package/dist/ui/{shared-lYtMadRU.js → shared-B1SAS_J-.js} +3 -3
- package/dist/ui/{shared-lYtMadRU.js.map → shared-B1SAS_J-.js.map} +1 -1
- package/dist/ui/{shared-CpI0Y8M5.js → shared-B4jgU8h9.js} +6 -6
- package/dist/ui/{shared-CpI0Y8M5.js.map → shared-B4jgU8h9.js.map} +1 -1
- package/dist/ui/{shared-Cxu1c35l.js → shared-B5aBCUi7.js} +30 -30
- package/dist/ui/{shared-Cxu1c35l.js.map → shared-B5aBCUi7.js.map} +1 -1
- package/dist/ui/{shared-CAe-US1q.js → shared-B9H7_Pji.js} +5 -5
- package/dist/ui/{shared-CAe-US1q.js.map → shared-B9H7_Pji.js.map} +1 -1
- package/dist/ui/{shared-Q2bgBaYo.js → shared-BAXr20S-.js} +4 -4
- package/dist/ui/{shared-Q2bgBaYo.js.map → shared-BAXr20S-.js.map} +1 -1
- package/dist/ui/{shared-CyEefFFb.js → shared-BDDUzH-f.js} +19 -19
- package/dist/ui/{shared-CyEefFFb.js.map → shared-BDDUzH-f.js.map} +1 -1
- package/dist/ui/{shared-BdhPI6dq.js → shared-BGmkeDeW.js} +3 -3
- package/dist/ui/{shared-BdhPI6dq.js.map → shared-BGmkeDeW.js.map} +1 -1
- package/dist/ui/{shared-DONIpq2q.js → shared-BHCQ60yN.js} +2 -2
- package/dist/ui/{shared-DONIpq2q.js.map → shared-BHCQ60yN.js.map} +1 -1
- package/dist/ui/{shared-CNmaAv64.js → shared-BHsjawAG.js} +8 -8
- package/dist/ui/{shared-CNmaAv64.js.map → shared-BHsjawAG.js.map} +1 -1
- package/dist/ui/{shared-DgjU9kOy.js → shared-BIQuK_nq.js} +4 -4
- package/dist/ui/{shared-DgjU9kOy.js.map → shared-BIQuK_nq.js.map} +1 -1
- package/dist/ui/{shared-icSQAj21.js → shared-BOe4W2FI.js} +3 -3
- package/dist/ui/{shared-icSQAj21.js.map → shared-BOe4W2FI.js.map} +1 -1
- package/dist/ui/{shared-BlxoOJSk.js → shared-BPpC08ip.js} +3 -3
- package/dist/ui/{shared-BlxoOJSk.js.map → shared-BPpC08ip.js.map} +1 -1
- package/dist/ui/{shared-BtiFL37J.js → shared-BdA3LPCB.js} +2 -2
- package/dist/ui/{shared-BtiFL37J.js.map → shared-BdA3LPCB.js.map} +1 -1
- package/dist/ui/{shared-CvR94vn4.js → shared-Be3nbWsd.js} +11 -11
- package/dist/ui/{shared-CvR94vn4.js.map → shared-Be3nbWsd.js.map} +1 -1
- package/dist/ui/{shared-Bl_nF_IH.js → shared-Bf30ZLoS.js} +8 -4
- package/dist/ui/shared-Bf30ZLoS.js.map +1 -0
- package/dist/ui/{shared-DijrJ_V-.js → shared-BguP_BaR.js} +7 -7
- package/dist/ui/{shared-DijrJ_V-.js.map → shared-BguP_BaR.js.map} +1 -1
- package/dist/ui/{shared-DPAVoWY0.js → shared-BoLbc2WD.js} +17 -2
- package/dist/ui/{shared-DPAVoWY0.js.map → shared-BoLbc2WD.js.map} +1 -1
- package/dist/ui/{shared-BkdBTYwx.js → shared-BttyOW4W.js} +3 -3
- package/dist/ui/{shared-BkdBTYwx.js.map → shared-BttyOW4W.js.map} +1 -1
- package/dist/ui/{shared-CQWLz8uT.js → shared-BumxsBlA.js} +10 -10
- package/dist/ui/{shared-CQWLz8uT.js.map → shared-BumxsBlA.js.map} +1 -1
- package/dist/ui/{shared-Dzu7tFiC.js → shared-Bw73ktBk.js} +3 -3
- package/dist/ui/{shared-Dzu7tFiC.js.map → shared-Bw73ktBk.js.map} +1 -1
- package/dist/ui/{shared-BhAYErSx.js → shared-C1B0GH0e.js} +4 -4
- package/dist/ui/{shared-BhAYErSx.js.map → shared-C1B0GH0e.js.map} +1 -1
- package/dist/ui/{shared-BQJQcGgj.js → shared-C2FsyYr7.js} +4 -4
- package/dist/ui/{shared-BQJQcGgj.js.map → shared-C2FsyYr7.js.map} +1 -1
- package/dist/ui/{shared-B9lw2Ryh.js → shared-C2RU1qjv.js} +4 -4
- package/dist/ui/{shared-B9lw2Ryh.js.map → shared-C2RU1qjv.js.map} +1 -1
- package/dist/ui/{shared-DQYNI9wO.js → shared-C42f07hJ.js} +5 -5
- package/dist/ui/{shared-DQYNI9wO.js.map → shared-C42f07hJ.js.map} +1 -1
- package/dist/ui/{shared-CqCZ8wMY.js → shared-C4LkPCU4.js} +3 -3
- package/dist/ui/{shared-CqCZ8wMY.js.map → shared-C4LkPCU4.js.map} +1 -1
- package/dist/ui/{shared-BhtpgOpa.js → shared-C4wSfz6k.js} +9 -9
- package/dist/ui/{shared-BhtpgOpa.js.map → shared-C4wSfz6k.js.map} +1 -1
- package/dist/ui/{shared-BHc2Izkj.js → shared-C9DZtSFH.js} +2 -2
- package/dist/ui/{shared-BHc2Izkj.js.map → shared-C9DZtSFH.js.map} +1 -1
- package/dist/ui/{shared-DW1YuiNS.js → shared-CA52ClGo.js} +2 -2
- package/dist/ui/{shared-DW1YuiNS.js.map → shared-CA52ClGo.js.map} +1 -1
- package/dist/ui/{shared-BbSbilkh.js → shared-CBciTwm6.js} +9 -9
- package/dist/ui/{shared-BbSbilkh.js.map → shared-CBciTwm6.js.map} +1 -1
- package/dist/ui/{shared-C-J32eBn.js → shared-CL3RLKDA.js} +16 -16
- package/dist/ui/{shared-C-J32eBn.js.map → shared-CL3RLKDA.js.map} +1 -1
- package/dist/ui/{shared-Ck8S4OxW.js → shared-CLq3-_hW.js} +3 -3
- package/dist/ui/{shared-Ck8S4OxW.js.map → shared-CLq3-_hW.js.map} +1 -1
- package/dist/ui/{shared-Q5WefT7G.js → shared-CMjK-Ucd.js} +3 -3
- package/dist/ui/{shared-Q5WefT7G.js.map → shared-CMjK-Ucd.js.map} +1 -1
- package/dist/ui/{shared-D3MAuEA3.js → shared-CPjpSFGh.js} +2 -2
- package/dist/ui/{shared-D3MAuEA3.js.map → shared-CPjpSFGh.js.map} +1 -1
- package/dist/ui/{shared-VshXGwXP.js → shared-CSPhENq3.js} +2 -2
- package/dist/ui/{shared-VshXGwXP.js.map → shared-CSPhENq3.js.map} +1 -1
- package/dist/ui/{shared-DJrJaE73.js → shared-CZJE4Bmp.js} +3 -3
- package/dist/ui/{shared-DJrJaE73.js.map → shared-CZJE4Bmp.js.map} +1 -1
- package/dist/ui/{shared-D7ONOwI7.js → shared-C_BhUL2I.js} +7 -7
- package/dist/ui/{shared-D7ONOwI7.js.map → shared-C_BhUL2I.js.map} +1 -1
- package/dist/ui/{shared-j-2peBIB.js → shared-CbeujwdU.js} +4 -4
- package/dist/ui/{shared-j-2peBIB.js.map → shared-CbeujwdU.js.map} +1 -1
- package/dist/ui/{shared-D5GrOEa2.js → shared-Cbf-o4Dt.js} +4 -4
- package/dist/ui/{shared-D5GrOEa2.js.map → shared-Cbf-o4Dt.js.map} +1 -1
- package/dist/ui/{shared-HwiPIajr.js → shared-CdNmeNHh.js} +3 -3
- package/dist/ui/{shared-HwiPIajr.js.map → shared-CdNmeNHh.js.map} +1 -1
- package/dist/ui/{shared-ZCFt-CPb.js → shared-CdQOMD8J.js} +3 -3
- package/dist/ui/{shared-ZCFt-CPb.js.map → shared-CdQOMD8J.js.map} +1 -1
- package/dist/ui/{shared-ClhXSGGK.js → shared-CdiPYlTh.js} +2 -2
- package/dist/ui/{shared-ClhXSGGK.js.map → shared-CdiPYlTh.js.map} +1 -1
- package/dist/ui/{shared-DA8_pVRZ.js → shared-CepLAhwm.js} +2 -2
- package/dist/ui/{shared-DA8_pVRZ.js.map → shared-CepLAhwm.js.map} +1 -1
- package/dist/ui/{shared-BrYKjrnM.js → shared-Ch82h_Fu.js} +6 -6
- package/dist/ui/{shared-BrYKjrnM.js.map → shared-Ch82h_Fu.js.map} +1 -1
- package/dist/ui/{shared-C4UrE8Fb.js → shared-Chp88all.js} +3 -3
- package/dist/ui/{shared-C4UrE8Fb.js.map → shared-Chp88all.js.map} +1 -1
- package/dist/ui/{shared-CWa80DTO.js → shared-Ci16s2rN.js} +9 -9
- package/dist/ui/{shared-CWa80DTO.js.map → shared-Ci16s2rN.js.map} +1 -1
- package/dist/ui/{shared-tksTLD6Q.js → shared-CiqNkoE1.js} +5 -5
- package/dist/ui/{shared-tksTLD6Q.js.map → shared-CiqNkoE1.js.map} +1 -1
- package/dist/ui/{shared-yt7DjSrq.js → shared-CpMhOq8F.js} +2 -2
- package/dist/ui/{shared-yt7DjSrq.js.map → shared-CpMhOq8F.js.map} +1 -1
- package/dist/ui/{shared-Dm0z5WUl.js → shared-CrWv5JKH.js} +6 -6
- package/dist/ui/{shared-Dm0z5WUl.js.map → shared-CrWv5JKH.js.map} +1 -1
- package/dist/ui/{shared-CQL3FGHc.js → shared-Csfi3Pti.js} +2 -2
- package/dist/ui/{shared-CQL3FGHc.js.map → shared-Csfi3Pti.js.map} +1 -1
- package/dist/ui/{shared-BKNRbm-V.js → shared-CuZt26rm.js} +2 -2
- package/dist/ui/{shared-BKNRbm-V.js.map → shared-CuZt26rm.js.map} +1 -1
- package/dist/ui/{shared-Guq3upiR.js → shared-Cws_z-TS.js} +2 -2
- package/dist/ui/{shared-Guq3upiR.js.map → shared-Cws_z-TS.js.map} +1 -1
- package/dist/ui/{shared-Bw_qZeIj.js → shared-D1KWuCg6.js} +2 -2
- package/dist/ui/{shared-Bw_qZeIj.js.map → shared-D1KWuCg6.js.map} +1 -1
- package/dist/ui/{shared-CuCZKwXW.js → shared-D66ju_Cb.js} +23 -23
- package/dist/ui/{shared-CuCZKwXW.js.map → shared-D66ju_Cb.js.map} +1 -1
- package/dist/ui/{shared-DYfX7NSM.js → shared-DGaQZXnw.js} +2 -2
- package/dist/ui/{shared-DYfX7NSM.js.map → shared-DGaQZXnw.js.map} +1 -1
- package/dist/ui/{shared-B3Hp8tOv.js → shared-DHy41sET.js} +6 -6
- package/dist/ui/{shared-B3Hp8tOv.js.map → shared-DHy41sET.js.map} +1 -1
- package/dist/ui/{shared-CXyd7IKi.js → shared-DKEOMQ6l.js} +2 -2
- package/dist/ui/{shared-CXyd7IKi.js.map → shared-DKEOMQ6l.js.map} +1 -1
- package/dist/ui/{shared-Ccmc8YO0.js → shared-DSUICuaJ.js} +33 -33
- package/dist/ui/{shared-Ccmc8YO0.js.map → shared-DSUICuaJ.js.map} +1 -1
- package/dist/ui/{shared-CL2iw_js.js → shared-DUPMRoO0.js} +13 -13
- package/dist/ui/{shared-CL2iw_js.js.map → shared-DUPMRoO0.js.map} +1 -1
- package/dist/ui/{shared-Dtp4eRul.js → shared-DVfdm6ah.js} +2 -2
- package/dist/ui/{shared-Dtp4eRul.js.map → shared-DVfdm6ah.js.map} +1 -1
- package/dist/ui/{shared-BJ5Ex32G.js → shared-DXM7d7lJ.js} +3 -3
- package/dist/ui/{shared-BJ5Ex32G.js.map → shared-DXM7d7lJ.js.map} +1 -1
- package/dist/ui/{shared-BFr6ld0e.js → shared-DXbMlcev.js} +2 -2
- package/dist/ui/{shared-BFr6ld0e.js.map → shared-DXbMlcev.js.map} +1 -1
- package/dist/ui/{shared-BUp3jv-N.js → shared-D_SkPtJ9.js} +6 -6
- package/dist/ui/{shared-BUp3jv-N.js.map → shared-D_SkPtJ9.js.map} +1 -1
- package/dist/ui/{shared-CdNomVzH.js → shared-Dd21k2ic.js} +4 -4
- package/dist/ui/{shared-CdNomVzH.js.map → shared-Dd21k2ic.js.map} +1 -1
- package/dist/ui/{shared-gRMbxmpu.js → shared-Dh0nHtLZ.js} +8 -8
- package/dist/ui/{shared-gRMbxmpu.js.map → shared-Dh0nHtLZ.js.map} +1 -1
- package/dist/ui/{shared-BKGJgjog.js → shared-DkOdSpSK.js} +3 -3
- package/dist/ui/{shared-BKGJgjog.js.map → shared-DkOdSpSK.js.map} +1 -1
- package/dist/ui/{shared-BMsh72Uq.js → shared-Dkph5ckT.js} +2 -2
- package/dist/ui/{shared-BMsh72Uq.js.map → shared-Dkph5ckT.js.map} +1 -1
- package/dist/ui/{shared-Be1HpDOB.js → shared-Dl1_Nx--.js} +3 -3
- package/dist/ui/{shared-Be1HpDOB.js.map → shared-Dl1_Nx--.js.map} +1 -1
- package/dist/ui/{shared-BQIZWOoJ.js → shared-Dm0IGbAf.js} +2 -2
- package/dist/ui/{shared-BQIZWOoJ.js.map → shared-Dm0IGbAf.js.map} +1 -1
- package/dist/ui/{shared-DSUtcU5S.js → shared-DnIkTpPr.js} +5 -5
- package/dist/ui/{shared-DSUtcU5S.js.map → shared-DnIkTpPr.js.map} +1 -1
- package/dist/ui/{shared-DsxGbYlV.js → shared-Docl_0tq.js} +3 -3
- package/dist/ui/{shared-DsxGbYlV.js.map → shared-Docl_0tq.js.map} +1 -1
- package/dist/ui/{shared-DZskrV26.js → shared-DprrHC72.js} +2 -2
- package/dist/ui/{shared-DZskrV26.js.map → shared-DprrHC72.js.map} +1 -1
- package/dist/ui/{shared-Bmw43Hwf.js → shared-DyKsJTZs.js} +2 -2
- package/dist/ui/{shared-Bmw43Hwf.js.map → shared-DyKsJTZs.js.map} +1 -1
- package/dist/ui/{shared-BLG88Pya.js → shared-FO7vfI3F.js} +4 -4
- package/dist/ui/{shared-BLG88Pya.js.map → shared-FO7vfI3F.js.map} +1 -1
- package/dist/ui/{shared-DLSd80D1.js → shared-HalAVHjv.js} +3 -3
- package/dist/ui/{shared-DLSd80D1.js.map → shared-HalAVHjv.js.map} +1 -1
- package/dist/ui/{shared-D1mMBLdj.js → shared-JvcI-LWp.js} +15 -15
- package/dist/ui/{shared-D1mMBLdj.js.map → shared-JvcI-LWp.js.map} +1 -1
- package/dist/ui/{shared-C6Hv_4O0.js → shared-K7Ym27yg.js} +2 -2
- package/dist/ui/{shared-C6Hv_4O0.js.map → shared-K7Ym27yg.js.map} +1 -1
- package/dist/ui/{shared-B39ln7oi.js → shared-SzlnwfJO.js} +3 -3
- package/dist/ui/{shared-B39ln7oi.js.map → shared-SzlnwfJO.js.map} +1 -1
- package/dist/ui/{shared-DgPn_Jll.js → shared-TrGbd1FY.js} +3 -3
- package/dist/ui/{shared-DgPn_Jll.js.map → shared-TrGbd1FY.js.map} +1 -1
- package/dist/ui/{shared-DrFb-XtA.js → shared-WhbuObEW.js} +2 -2
- package/dist/ui/{shared-DrFb-XtA.js.map → shared-WhbuObEW.js.map} +1 -1
- package/dist/ui/{shared-DiFQljcq.js → shared-XcSKDp6N.js} +11 -11
- package/dist/ui/{shared-DiFQljcq.js.map → shared-XcSKDp6N.js.map} +1 -1
- package/dist/ui/{shared-CMAg58rY.js → shared-Z4uBJU6I.js} +7 -6
- package/dist/ui/shared-Z4uBJU6I.js.map +1 -0
- package/dist/ui/{shared-BnUptuUp.js → shared-bAgeiRa5.js} +2 -2
- package/dist/ui/{shared-BnUptuUp.js.map → shared-bAgeiRa5.js.map} +1 -1
- package/dist/ui/{shared-BxMvSjey.js → shared-cgXG7OgZ.js} +5 -5
- package/dist/ui/{shared-BxMvSjey.js.map → shared-cgXG7OgZ.js.map} +1 -1
- package/dist/ui/{shared-u4CG2kQJ.js → shared-eZ0SB_zm.js} +2 -2
- package/dist/ui/{shared-u4CG2kQJ.js.map → shared-eZ0SB_zm.js.map} +1 -1
- package/dist/ui/{shared-L90bWW8e.js → shared-frKFb79C.js} +2 -2
- package/dist/ui/{shared-L90bWW8e.js.map → shared-frKFb79C.js.map} +1 -1
- package/dist/ui/{shared-Dd34nhkw.js → shared-hAayNSRA.js} +3 -3
- package/dist/ui/{shared-Dd34nhkw.js.map → shared-hAayNSRA.js.map} +1 -1
- package/dist/ui/{shared-DzC64cpp.js → shared-j_J16p2B.js} +2 -2
- package/dist/ui/{shared-DzC64cpp.js.map → shared-j_J16p2B.js.map} +1 -1
- package/dist/ui/{shared-DX7HRIV-.js → shared-tqpl5N3g.js} +6 -6
- package/dist/ui/{shared-DX7HRIV-.js.map → shared-tqpl5N3g.js.map} +1 -1
- package/dist/ui/{shared-BS5dBMpA.js → shared-y-6_ZDts.js} +2 -2
- package/dist/ui/{shared-BS5dBMpA.js.map → shared-y-6_ZDts.js.map} +1 -1
- package/dist/ui/{shared-Cv5v_MP1.js → shared-zG6e1Rhz.js} +13 -13
- package/dist/ui/{shared-Cv5v_MP1.js.map → shared-zG6e1Rhz.js.map} +1 -1
- package/dist/ui/testing.js +1 -1
- package/package.json +4 -4
- package/dist/docs/cli-browser.md +0 -232
- package/dist/docs/database-browser.md +0 -115
- package/dist/docs/keyboard.md +0 -63
- package/dist/docs/mcp.md +0 -86
- package/dist/ui/shared-Bl_nF_IH.js.map +0 -1
- package/dist/ui/shared-CMAg58rY.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { D as subscribeSessionIdentity, E as sessionIdentity, w as captureSessionIdentity } from "./shared-poc11xxo.js";
|
|
2
2
|
import { Ct as addHostListener, gt as defineMessages, j as isJsonType, kt as portalRoot, rn as shell } from "./shared-DJZjSi3J.js";
|
|
3
|
-
import { d as draftSchemaKey, u as createRecordDrafts } from "./shared-
|
|
4
|
-
import { B as toast, C as prefersPages, F as setRecordMutationPendingProbe, L as state, X as el, c as columnLabel, i as api, o as captureNavigation, st as ownedBy, ut as connectionGeneration } from "./shared-
|
|
3
|
+
import { d as draftSchemaKey, u as createRecordDrafts } from "./shared-BHsjawAG.js";
|
|
4
|
+
import { B as toast, C as prefersPages, F as setRecordMutationPendingProbe, L as state, X as el, c as columnLabel, i as api, o as captureNavigation, st as ownedBy, ut as connectionGeneration } from "./shared-BoLbc2WD.js";
|
|
5
5
|
import "./shared-CRr4kJXB.js";
|
|
6
|
-
import { c as updateAttempts, l as updateOwnerKey } from "./shared-
|
|
7
|
-
import { n as canEditRow } from "./shared-
|
|
6
|
+
import { c as updateAttempts, l as updateOwnerKey } from "./shared-Chp88all.js";
|
|
7
|
+
import { n as canEditRow } from "./shared-BHCQ60yN.js";
|
|
8
8
|
import { t as validateRecordEdits } from "./shared-BqjEZ3bN.js";
|
|
9
|
-
import { t as captureRecordWriteRefresh } from "./shared-
|
|
9
|
+
import { t as captureRecordWriteRefresh } from "./shared-CdQOMD8J.js";
|
|
10
10
|
import "react";
|
|
11
11
|
import "react/jsx-runtime";
|
|
12
12
|
defineMessages({
|
|
@@ -422,6 +422,7 @@ var autosaveOwner;
|
|
|
422
422
|
function cancelRecordAutosave() {
|
|
423
423
|
autosaveCancellation++;
|
|
424
424
|
}
|
|
425
|
+
/** @public the database browser's (scripts/boundary/entries.json, "host") */
|
|
425
426
|
function recordAutosavePending() {
|
|
426
427
|
return autosaveIdentity !== void 0 && autosaveIdentity === sessionIdentity() && autosaveOwner !== void 0 && updateAttempts.get(autosaveOwner)?.phase !== "uncertain";
|
|
427
428
|
}
|
|
@@ -699,4 +700,4 @@ function confirmUpdate(table, key, values, originals) {
|
|
|
699
700
|
}
|
|
700
701
|
export { stagedOriginal as C, suspendDraft as D, subscribeStaged as E, takeFieldFocus as O, stagedFeedback as S, stagedVersion as T, sameRow as _, captureRecordAutosaveGuard as a, stagedDiscardVersion as b, dismissSaveFeedback as c, pendingColumns as d, pendingCount as f, retainedValues as g, resumeDraft as h, cancelRecordAutosave as i, takeTheirs as k, draftNeedsReview as l, registerInput as m, applyStaged as n, dirtyDraft as o, refreshEditValidation as p, applyingStaged as r, discardStaged as s, activateDraft as t, draftSchemaChanged as u, stage as v, stagedValue as w, stagedEditErrors as x, stagedAttempt as y };
|
|
701
702
|
|
|
702
|
-
//# sourceMappingURL=shared-
|
|
703
|
+
//# sourceMappingURL=shared-Z4uBJU6I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-Z4uBJU6I.js","names":["say"],"sources":["../../../kit/src/client/copy/record/components/WriteConfirm.ts","../../../kit/src/client/copy/record/write.ts","../../../kit/src/client/write.js"],"sourcesContent":["/** What WriteConfirm says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n enableWriteMode: 'Enable write mode?',\n enableEditingOfExisting: 'Enable editing of existing records in',\n fieldChangesStayPending: 'Field changes stay pending until you review and apply them together.',\n theReviewNamesTheRecord: 'The review names the record, changed values, and SQL statement.',\n anUpdateThatWould: 'An update that would touch more than one row is refused.',\n writeModeStaysOnForThisDatabase: 'Write mode stays on for this database until you turn it off, including after a reload.',\n itAppliesToThisDatabase: 'It applies to this database only — switching connections does not carry it over.',\n keepViewing: 'Keep viewing',\n enableWriteModeButton: 'Enable write mode',\n});\n","/** What write says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../messages.js';\n\nexport const say = defineMessages({\n resolveThePendingOrUnconfirmed: 'Resolve the pending or unconfirmed change before leaving this view.',\n waitForThePending: 'Wait for the pending record update before changing modes.',\n discardPendingRecordChanges: 'Discard pending record changes?',\n theseFieldChangesHaveNotBeen: 'These field changes have not been applied.',\n discardChanges: 'Discard changes',\n thisConnectionIsRead: 'This connection is read-only.',\n unsavedChangesWereRetained: 'Unsaved changes were retained in this tab. Review them when you return.',\n theRecordConnectionOrTable: 'The record, connection or table definition changed. Review the current record before applying changes.',\n theRecordChangedBefore: 'The record changed before saving. Review it and save again.',\n updatedColumnsOnTheOriginal: {\n one: 'Updated {count} column on the original record in {connection}.',\n other: 'Updated {count} columns on the original record in {connection}.',\n },\n changesSaved: 'Changes saved',\n updatedColumns: { one: 'Updated {count} column on {name}.', other: 'Updated {count} columns on {name}.' },\n applyThisChange: 'Apply this change?',\n applyChanges: { one: 'Apply {count} change?', other: 'Apply {count} changes?' },\n unknownTable: 'Unknown table.',\n thisIsAView: 'This is a view. Views are read-only.',\n thisTableHasNoPrimary: 'This table has no primary key, so there is no way to identify one row safely.',\n parameters: 'parameters {params}',\n theOriginalConnection: 'the original connection',\n});\n","/**\n * Write mode.\n *\n * Workbench defaults to read-only; apps enable editing on writable connections.\n * The connection the browsing path uses remains read-only, so looking\n * around cannot write, even after editing is enabled. Editing goes through a\n * separate connection that the server opens lazily, the first time it is\n * actually asked to write.\n *\n * Editing preferences are remembered separately per connection and workspace.\n * Workbench enabling still requires explicit confirmation.\n * It never grants server permission or carries from one database to another.\n *\n * The real guard is on the server, not here. This file makes the state\n * obvious and asks for confirmation; the server independently refuses any\n * update whose WHERE clause does not match exactly one row.\n */\nimport { ownedBy } from './requestIdentity.js';\nimport {\n api,\n captureNavigation,\n columnLabel,\n currentEntry,\n el,\n loadJson,\n prefersPages,\n render,\n saveJson,\n setRecordMutationPendingProbe,\n state,\n toast,\n} from './core.js';\nimport { ask, confirmFor } from './prompt.js';\nimport { WriteConfirmDialog } from './components/WriteConfirm.js';\nimport { booleanChoices, canEditRow } from './rowEditing.js';\nimport { captureSessionIdentity, sessionIdentity, subscribeSessionIdentity } from './sessionIdentity.js';\nimport { updateAttempts, updateOwnerKey } from './updateAttempts.js';\nimport { createRecordDrafts, draftSchemaKey } from './recordDrafts.js';\nimport { shell } from './shellMode.js';\nimport { validateRecordEdits } from './recordEditValidation.js';\nimport { captureRecordWriteRefresh } from './recordWriteRefresh.js';\nimport { connectionGeneration } from './connectionTransition.js';\nimport { plural } from './locale.js';\nimport { say } from './copy/record/write.js';\nimport { isJsonType } from '@mistriwork/engine/shared/schema.js';\nimport { addHostListener, portalRoot, shellBody } from './shellHost.js';\n\nsetRecordMutationPendingProbe(recordAutosavePending);\n\n/* Write mode is remembered per connection.\n Per connection, not globally: switching from the demo to production must\n not silently inherit permission to edit it. Each database is opted into\n separately, and the choice sticks until it is turned off. */\nconst WRITE_KEY = 'mistri.write.v1';\nconst APP_WRITE_KEY = 'mistri.app-editing.v1';\n\nconst connectionKey = () => state.activeConnection ?? 'default';\nconst writableConnection = () => Boolean(state.connections?.find((c) => c.id === state.activeConnection)?.writable);\n\nfunction rememberedWrite() {\n if (prefersPages()) return writableConnection() && loadJson(APP_WRITE_KEY, {})[connectionKey()] !== false;\n return loadJson(WRITE_KEY, {})[connectionKey()] === true;\n}\n\nfunction rememberWrite(on) {\n const storageKey = prefersPages() ? APP_WRITE_KEY : WRITE_KEY;\n const all = loadJson(storageKey, {});\n all[connectionKey()] = on;\n saveJson(storageKey, all);\n}\n\nexport function initWriteMode() {\n // Restored without asking again: the confirmation was given for this\n // database and has not been withdrawn.\n setWriteMode(rememberedWrite(), { remember: false });\n}\n\n/** Mode changes must not hide pending work or interrupt an acknowledged save. */\nexport async function prepareEditingExit() {\n if (shell().mutations.hasUnresolved()) {\n toast(say('resolveThePendingOrUnconfirmed'), 'error');\n return false;\n }\n if (applyingStaged()) {\n toast(say('waitForThePending'), 'error');\n return false;\n }\n const connection = state.activeConnection;\n const schema = state.schema;\n const entry = currentEntry();\n const mode = prefersPages();\n const captured = staged;\n if (\n pendingCount() &&\n !(await confirmFor({\n title: say('discardPendingRecordChanges'),\n body: say('theseFieldChangesHaveNotBeen'),\n confirmLabel: say('discardChanges'),\n }))\n )\n return false;\n if (\n connection !== state.activeConnection ||\n schema !== state.schema ||\n entry !== currentEntry() ||\n mode !== prefersPages() ||\n captured !== staged ||\n applyingStaged() ||\n shell().mutations.hasUnresolved()\n )\n return false;\n discardStaged();\n return true;\n}\n\n/** @public the database browser's (scripts/boundary/entries.json, \"host\") */\nexport async function toggleWriteMode() {\n if (state.canWrite) {\n if (await prepareEditingExit()) setWriteMode(false);\n return;\n }\n const connection = state.activeConnection;\n const schema = state.schema;\n const app = prefersPages();\n if (app && !writableConnection()) {\n toast(say('thisConnectionIsRead'), 'error');\n return;\n }\n if ((app || (await confirmWrite())) && connection === state.activeConnection && schema === state.schema && app === prefersPages())\n setWriteMode(true);\n}\n\n/** Re-evaluate on connection switch, since the setting is per database. */\nexport function syncWriteMode() {\n setWriteMode(rememberedWrite(), { remember: false });\n}\n\nfunction setWriteMode(on, { remember = true } = {}) {\n state.canWrite = on;\n if (remember) rememberWrite(on);\n /* The indicator is on <body> rather than the button, so it can colour the\n window frame. Being in write mode should be visible from across the room,\n not something you have to go looking for. */\n shellBody().classList.toggle('write-mode', on && !prefersPages());\n // Explicit mode exits discard above; automatic connection changes retain drafts.\n if (!on && remember) discardStaged();\n render();\n}\n\n/**\n * A real confirmation, naming the database — `components/WriteConfirm.tsx`.\n * \"Are you sure?\" teaches nothing; the name of the thing you are about to\n * be able to change does.\n */\nfunction confirmWrite() {\n return ask(WriteConfirmDialog, { label: state.schema.label });\n}\n\n/* ---------- staged edits ----------\n\n Every submission captures the whole draft as one update. An opted-in App\n can submit on an owned blur; Workbench keeps explicit review and apply.\n\n Staging is keyed by table and row, so walking away and back does not\n silently carry pending edits onto a different row. */\n\nconst drafts = createRecordDrafts();\nconst emptyDraft = () => ({\n connection: null,\n table: '',\n key: {},\n schemaKey: '',\n needsReview: false,\n manualSaveRequired: false,\n values: {},\n originals: {},\n inputs: {},\n});\nlet staged = emptyDraft();\nsubscribeSessionIdentity(() => {\n cancelRecordAutosave();\n drafts.clear();\n staged = emptyDraft();\n tell();\n});\n\nexport function activateDraft(table, key) {\n const next = drafts.acquire({ connection: state.activeConnection ?? null, table: table.id, key }, draftSchemaKey(table));\n if (next === staged) return staged;\n staged = next;\n tell();\n return staged;\n}\n\nexport function suspendDraft(draft) {\n const retained = draft === staged && prefersPages() && Object.keys(draft.values).length > 0 && !updateAttempts.get(draft);\n if (draft === staged) cancelRecordAutosave();\n drafts.suspend(draft);\n feedback.delete(draft);\n if (draft === staged) staged = emptyDraft();\n if (retained) toast(say('unsavedChangesWereRetained'), 'info');\n}\n\n/**\n * The record the reader has an unsaved draft of, for live sync (liveInvalidate.ts): a change another person made to\n * it does not reach the form, it is said beside it (components/LiveNotice.tsx).\n * @returns {{ table: string, key: Record<string, unknown>, originals: Record<string, unknown>, values: Record<string, unknown> } | undefined}\n */\nexport const dirtyDraft = () =>\n staged.connection === (state.activeConnection ?? null) && Object.keys(staged.values).length ? staged : undefined;\n\n/**\n * Take another person's value for one field of the draft: the form shows it, and Save checks against it.\n * @param {string} column\n * @param {unknown} value\n */\nexport function takeTheirs(column, value) {\n if (!Object.keys(staged.values).length) return;\n staged.values[column] = value;\n staged.originals[column] = value;\n tell();\n}\n\nexport const draftNeedsReview = (table, key) => sameRow(table, key) && staged.needsReview;\n/** @public the database browser's (scripts/boundary/entries.json, \"host\") */\nexport const draftRequiresManualSave = (table, key) => sameRow(table, key) && staged.manualSaveRequired;\nexport const draftSchemaChanged = (table) => staged.schemaKey !== draftSchemaKey(table);\nexport const retainedValues = () => ({ ...staged.values });\nexport const stagedOriginal = (column) => (staged.needsReview ? undefined : staged.originals[column]);\n\nexport function resumeDraft(table, key) {\n if (!sameRow(table.id, key) || draftSchemaChanged(table) || !canEditRow(table, key) || stagedAttempt(table.id, key)) return;\n staged.needsReview = false;\n tell();\n}\n\naddHostListener(window, 'beforeunload', (event) => {\n if (!drafts.hasPending()) return;\n event.preventDefault();\n event.returnValue = '';\n});\n\nexport function pendingCount() {\n return staged.connection === (state.activeConnection ?? null) ? Object.keys(staged.values).length : 0;\n}\n\n/**\n * Whether what is staged belongs to the row on screen.\n *\n * The connection is part of the answer. Keyed by table and key alone, an edit\n * staged against staging's `customer:4` showed as pending on production's\n * `customer:4` — the same table name and the same id, a different database,\n * and one click from being written to the wrong one.\n */\nfunction sameRow(table, key) {\n return updateOwnerKey(staged) === updateOwnerKey({ connection: state.activeConnection ?? null, table, key });\n}\n\nexport function discardStaged() {\n cancelRecordAutosave();\n editErrors.delete(staged);\n clearServerErrors(staged);\n discards.set(staged, (discards.get(staged) ?? 0) + 1);\n if (staged.connection === (state.activeConnection ?? null)) {\n staged.values = {};\n staged.originals = {};\n staged.needsReview = false;\n staged.manualSaveRequired = false;\n feedback.delete(staged);\n } else staged = emptyDraft();\n tell();\n}\n\n/* A flag's two stored values and whether a row may be edited live in\n rowEditing.js, where a grid's cell asks them too; re-exported for the\n record editors that have always asked here. */\nexport { booleanChoices, canEditRow };\n\n/* The editor and the pending bar are components (components/Editable.tsx); they\n read this store and tick with it. */\nconst listeners = new Set();\nconst feedback = new WeakMap();\nconst discards = new WeakMap();\n/** @type {WeakMap<import('./recordDrafts.js').RecordDraft, Readonly<Record<string, string>>>} */\nconst editErrors = new WeakMap();\n/* The fields a refused save named, marked on the record until each is edited.\n Kept apart from the preflight's errors, which are recomputed from the draft\n on every edit and would otherwise wipe a mark the reader has not touched. */\n/** @type {WeakMap<import('./recordDrafts.js').RecordDraft, Readonly<Record<string, string>>>} */\nconst serverErrors = new WeakMap();\n/** @type {WeakMap<Readonly<Record<string, string>>, { client: Readonly<Record<string, string>>, errors: Readonly<Record<string, string>> }>} */\nconst mergedErrors = new WeakMap();\n/* The first field a refused explicit Save marked. Its editor may not be drawn\n yet — an unopened field opens because it is marked — so the editor takes\n the focus when it is, once. */\n/** @type {{ draft: import('./recordDrafts.js').RecordDraft, field: string } | null} */\nlet fieldFocus = null;\nconst noEditErrors = Object.freeze({});\nlet version = 0;\nfunction tell() {\n version += 1;\n for (const fn of listeners) fn();\n}\nexport function subscribeStaged(fn) {\n listeners.add(fn);\n const unsubscribe = updateAttempts.subscribe(fn);\n return () => {\n listeners.delete(fn);\n unsubscribe();\n };\n}\nexport const stagedVersion = () => version + updateAttempts.version();\n/** @returns {import('./updateAttempts.js').UpdateAttempt | undefined} */\nexport const stagedAttempt = (table, key) => updateAttempts.get({ connection: state.activeConnection ?? null, table, key });\nexport const stagedFeedback = (table, key) => (sameRow(table, key) ? feedback.get(staged) : undefined);\nexport const stagedDiscardVersion = (table, key) => (sameRow(table, key) ? (discards.get(staged) ?? 0) : 0);\n/** @returns {Readonly<Record<string, string>>} */\nexport const stagedEditErrors = (tableId, key) => (sameRow(tableId, key) ? draftErrors(staged) : noEditErrors);\n\n/* The preflight's word wins over a refusal's for the same field: it is about\n the value on screen now, the refusal about the one that was sent. */\nfunction draftErrors(draft) {\n const client = editErrors.get(draft) ?? noEditErrors;\n const server = serverErrors.get(draft);\n if (!server) return client;\n const cached = mergedErrors.get(server);\n if (cached?.client === client) return cached.errors;\n const errors = Object.freeze({ ...server, ...client });\n mergedErrors.set(server, { client, errors });\n return errors;\n}\n\n/** Whether this field's editor should take the focus a refused Save left for it. Consumed. */\nexport function takeFieldFocus(tableId, key, column) {\n if (!fieldFocus || fieldFocus.draft !== staged || fieldFocus.field !== column || !sameRow(tableId, key)) return false;\n fieldFocus = null;\n return true;\n}\n\n/* A column's own mark, and its row-defined fields' (`specs.capacity`): the\n whole object is what was staged again. */\nfunction clearServerError(draft, name) {\n const server = serverErrors.get(draft);\n const of = (field) => field === name || field.startsWith(`${name}.`);\n if (fieldFocus?.draft === draft && of(fieldFocus.field)) fieldFocus = null;\n if (!server || !Object.keys(server).some(of)) return;\n const rest = Object.fromEntries(Object.entries(server).filter(([field]) => !of(field)));\n if (Object.keys(rest).length) serverErrors.set(draft, Object.freeze(rest));\n else serverErrors.delete(draft);\n}\n\nfunction clearServerErrors(draft) {\n serverErrors.delete(draft);\n if (fieldFocus?.draft === draft) fieldFocus = null;\n}\n\n/* A field is on screen when its editor — open or not — is registered and\n drawn. Presence, not focusability: a pending save disables the launchers. */\nfunction fieldOnScreen(draft, name) {\n const root = draft.inputs[name]?.element;\n return Boolean(root?.isConnected && !root.closest('[hidden], [inert], [aria-hidden=\"true\"]'));\n}\n\n/**\n * Mark the fields a refused save named — the New form's contract, through the\n * same shape check — on the record they are drawn on, and say in the summary\n * only what cannot be marked: fields this record does not show, or none named\n * at all. An explicit Save leaves the focus on the first marked field in\n * catalog order; a blur save leaves it where the reader moved it.\n * @returns {string} The summary, empty when every named field is marked.\n */\nfunction markRefusal(draft, table, result, focus) {\n const marks = Object.create(null);\n const unplaced = [];\n for (const { field, message } of result.fields ?? []) {\n // A row-defined field is `column.key` (definedFields.ts), marked where its own editor is registered under that name.\n const column = table.columns?.find((candidate) => candidate.name === field.split('.')[0]);\n if (column && fieldOnScreen(draft, field)) marks[field] = message;\n else unplaced.push(column ? `${columnLabel(table.id, field) ?? field}: ${message}` : '');\n }\n const marked = Object.keys(marks);\n if (marked.length) serverErrors.set(draft, Object.freeze(marks));\n else clearServerErrors(draft);\n const first =\n table.columns?.find((column) => Object.hasOwn(marks, column.name))?.name ??\n marked.find((field) => table.columns?.some((column) => field.startsWith(`${column.name}.`)));\n fieldFocus = focus && first ? { draft, field: first } : fieldFocus?.draft === draft ? null : fieldFocus;\n if (marked.length && !unplaced.length) return '';\n return [result.message, ...unplaced.filter(Boolean)].join(' ');\n}\nexport function dismissSaveFeedback() {\n feedback.delete(staged);\n tell();\n}\n\nfunction readEditControls(draft) {\n /** @type {Record<string, import('./recordEditValidation.js').RecordEditControlState>} */\n const controls = Object.create(null);\n for (const [name, registered] of Object.entries(draft.inputs)) {\n if (!registered.element.isConnected || !registered.readState) continue;\n try {\n const value = registered.readState();\n if (!value || typeof value !== 'object' || Array.isArray(value) || 'then' in value) throw new Error();\n const { unresolvedReference, invalidInput } = value;\n if (\n (unresolvedReference !== undefined && typeof unresolvedReference !== 'boolean') ||\n (invalidInput !== undefined && typeof invalidInput !== 'boolean')\n )\n throw new Error();\n controls[name] = { unresolvedReference, invalidInput };\n } catch {\n // Control faults never expose callback diagnostics or permit a partial save.\n controls[name] = { invalidInput: true };\n }\n }\n return controls;\n}\n\nfunction errorControl(draft, name) {\n const root = draft.inputs[name]?.element;\n if (!root?.isConnected || root.closest('[hidden], [inert], [aria-hidden=\"true\"]')) return;\n const selector =\n 'input:not(:disabled):not([type=\"hidden\"]), textarea:not(:disabled), select:not(:disabled), button:not(:disabled), [tabindex]:not([tabindex=\"-1\"])';\n return root.matches(selector) ? root : root.querySelector(selector);\n}\n\nfunction publishEditValidation(draft, errors) {\n const previous = editErrors.get(draft) ?? noEditErrors;\n const names = Object.keys(errors);\n let changed = names.length !== Object.keys(previous).length || names.some((name) => errors[name] !== previous[name]);\n editErrors.set(draft, changed ? errors : previous);\n const inaccessible = names.filter((name) => !errorControl(draft, name));\n const priorFeedback = feedback.get(draft);\n if (inaccessible.length) {\n const message = inaccessible.map((name) => `${name}: ${errors[name]}`).join(' ');\n if (priorFeedback?.source !== 'validation' || priorFeedback.message !== message) {\n feedback.set(draft, { phase: 'error', source: 'validation', message });\n changed = true;\n }\n } else if (priorFeedback?.source === 'validation') {\n feedback.delete(draft);\n changed = true;\n }\n return changed;\n}\n\n/** Corrections may clear attempted validation, but mounting stays quiet. */\nexport function refreshEditValidation(table, key) {\n if (!prefersPages() || !sameRow(table.id, key) || !editErrors.has(staged)) return;\n const captured = staged,\n revision = stagedVersion();\n const currentTable = state.schema?.tables?.find((candidate) => candidate.id === table.id) ?? table;\n const errors = validateRecordEdits(currentTable, captured.values, readEditControls(captured));\n if (captured !== staged || revision !== stagedVersion() || !sameRow(table.id, key)) return;\n if (publishEditValidation(captured, errors)) tell();\n}\n\n/** What is staged for a column of the row on screen, or undefined. */\nexport const stagedValue = (column) => (staged.needsReview ? undefined : staged.values[column]);\nexport const pendingColumns = () => Object.keys(staged.values);\n\n/**\n * Stage one change. Typing a value and then typing the original back is not\n * a change. Exported for the editor component.\n */\nexport function stage(table, key, column, value, original) {\n const known = table.columns?.find((c) => c.name === column.name);\n // A declared transition moves only through the record's actions.\n if (column.writable === false || column.changesBy === 'actions' || known?.writable === false || known?.changesBy === 'actions') return;\n // Freeze before an autosave publishes pending state. Other staged operations\n // (notably Undo reconciliation) still preserve edits begun while they settle.\n if (stagedAttempt(table.id, key) || (recordAutosavePending() && sameRow(table.id, key))) return;\n activateDraft(table, key);\n if (staged.needsReview) return;\n feedback.delete(staged);\n // An edited field is the reader's answer to its mark; the others keep theirs.\n clearServerError(staged, column.name);\n if (Object.hasOwn(staged.originals, column.name)) original = staged.originals[column.name];\n // Text inputs stringify numbers and booleans, but NULL is not the text \"null\".\n const unchanged = value === null || original === null ? value === original : String(value) === String(original);\n if (unchanged) {\n delete staged.values[column.name];\n delete staged.originals[column.name];\n } else {\n staged.values[column.name] = value;\n staged.originals[column.name] = original;\n /* A row-defined field (DefinedFields.tsx) is staged under `column.key`\n and saved as its column's whole object: the object it was read in and\n how its box's text becomes a value ride with the draft. */\n if (column.defined) (staged.folds ??= {})[column.name] = column.defined;\n }\n refreshEditValidation(table, key);\n tell();\n}\n\n/* What is sent: each row-defined field folded into its column's object, as\n JSON text (the server writes and judges the whole object). */\nfunction folded(draft, values, originals) {\n const folds = draft.folds ?? {};\n const fields = Object.keys(values).filter((name) => Object.hasOwn(folds, name));\n if (!fields.length) return { values, originals };\n const objects = {};\n const sent = { ...values },\n guarded = { ...originals };\n for (const name of fields) {\n const { column, object, toValue } = folds[name];\n const next = (objects[column] ??= { ...object });\n const value = toValue(values[name]);\n if (value === undefined) delete next[name.slice(column.length + 1)];\n else next[name.slice(column.length + 1)] = value;\n delete sent[name];\n delete guarded[name];\n }\n for (const [column, object] of Object.entries(objects)) sent[column] = JSON.stringify(object);\n return { values: sent, originals: guarded };\n}\n\n/** The editor's element, kept so a successful write can confirm in place.\n * @param {() => import('./recordEditValidation.js').RecordEditControlState} [readState]\n */\nexport function registerInput(table, key, column, input, onCommitted, readState) {\n activateDraft(table, key);\n const captured = staged,\n registration = { element: input, onCommitted, readState };\n Object.defineProperty(captured.inputs, column, { value: registration, configurable: true, writable: true, enumerable: true });\n return () => {\n if (captured.inputs[column] === registration) delete captured.inputs[column];\n };\n}\n\nexport { sameRow };\n\n/* An update's guard names each changed column at the value it was read with —\n but a JSON column's, which no engine compares: it is written whole. */\nfunction comparable(table, originals) {\n const json = new Set((table.columns ?? []).filter((column) => isJsonType(column.type)).map((column) => column.name));\n return json.size ? Object.fromEntries(Object.entries(originals).filter(([column]) => !json.has(column))) : originals;\n}\n\nlet applying = false;\nexport const applyingStaged = () => applying;\nlet autosaveCancellation = 0;\n/** @type {ReturnType<typeof captureSessionIdentity> | undefined} */\nlet autosaveIdentity;\n/** @type {import('./updateAttempts.js').UpdateOwner | undefined} */\nlet autosaveOwner;\n/** Deferred intent only: an already dispatched write still settles normally. */\nexport function cancelRecordAutosave() {\n autosaveCancellation++;\n}\n/** @public the database browser's (scripts/boundary/entries.json, \"host\") */\nexport function recordAutosavePending() {\n // Ordinary uncertainty keeps the record locked, not every route. Tenant\n // uncertainty still has its independent stronger navigation gate in core.\n return (\n autosaveIdentity !== undefined &&\n autosaveIdentity === sessionIdentity() &&\n autosaveOwner !== undefined &&\n updateAttempts.get(autosaveOwner)?.phase !== 'uncertain'\n );\n}\n\n/** Capture only for a fresh user edit leaving its complete interaction surface.\n * This predicate does not schedule or send anything. The interaction owner must\n * also prove its mount, picker state and current App save policy at dispatch. */\nexport function captureRecordAutosaveGuard(table, key, stillEditing) {\n const captured = staged,\n identity = captureSessionIdentity(),\n schema = state.schema;\n const capturedKey = { ...key },\n revision = stagedVersion();\n const cancellation = autosaveCancellation;\n const navigation = captureNavigation();\n const current = () => {\n try {\n return (\n typeof stillEditing === 'function' &&\n stillEditing() === true &&\n cancellation === autosaveCancellation &&\n prefersPages() &&\n navigation() &&\n captured === staged &&\n identity === sessionIdentity() &&\n schema === state.schema &&\n revision === stagedVersion() &&\n sameRow(table.id, capturedKey) &&\n pendingCount() > 0 &&\n !staged.needsReview &&\n !staged.manualSaveRequired &&\n !applying &&\n !stagedAttempt(table.id, capturedKey) &&\n !draftSchemaChanged(table) &&\n canEditRow(table, capturedKey)\n );\n } catch {\n return false;\n }\n };\n // An initially ineligible draft cannot be armed later by Resume, policy\n // changes, another acknowledgement or programmatic focus restoration.\n return current() ? current : () => false;\n}\n\n/**\n * @param {(opts?: { inPlace?: boolean }) => void} [onDone]\n * @param {{ trigger?: 'explicit'|'blur', guard?: () => boolean }} [options]\n */\nexport async function applyStaged(table, key, onDone = undefined, options = {}) {\n const trigger = options.trigger ?? 'explicit';\n if (trigger !== 'explicit' && trigger !== 'blur') return;\n const blur = trigger === 'blur';\n // Do not cancel the supplied blur capture before checking it.\n if (!blur) cancelRecordAutosave();\n const guard = () => {\n try {\n return typeof options.guard === 'function' && options.guard() === true;\n } catch {\n return false;\n }\n };\n if (blur && (!prefersPages() || staged.manualSaveRequired || !guard())) return;\n if (applying || staged.needsReview || stagedAttempt(table.id, key) || !sameRow(table.id, key)) return;\n if (!pendingCount()) {\n if (!blur && staged.manualSaveRequired) {\n staged.manualSaveRequired = false;\n editErrors.delete(staged);\n clearServerErrors(staged);\n feedback.delete(staged);\n tell();\n }\n return;\n }\n const currentTable = state.schema?.tables ? state.schema.tables.find((candidate) => candidate.id === table.id) : table;\n if (\n !currentTable ||\n draftSchemaChanged(currentTable) ||\n draftSchemaChanged(table) ||\n Object.keys(staged.values).some((name) => {\n const column = currentTable.columns?.find((c) => c.name === name);\n return column?.writable === false || column?.changesBy === 'actions';\n })\n )\n return;\n const app = prefersPages();\n if (app && !canEditRow(currentTable, key)) return;\n const captured = staged;\n const connection = captured.connection;\n const staging = { ...staged.values };\n const { values, originals } = folded(captured, staging, { ...staged.originals });\n key = { ...key };\n const schema = state.schema;\n const identity = captureSessionIdentity();\n const generation = connectionGeneration();\n const navigation = blur ? captureNavigation() : () => true;\n const cancellation = autosaveCancellation,\n revision = stagedVersion();\n if (app) {\n const errors = validateRecordEdits(currentTable, values, readEditControls(captured));\n if (\n captured !== staged ||\n revision !== stagedVersion() ||\n schema !== state.schema ||\n identity !== sessionIdentity() ||\n cancellation !== autosaveCancellation ||\n !sameRow(table.id, key) ||\n !canEditRow(currentTable, key) ||\n (blur && !guard())\n )\n return;\n const changed = publishEditValidation(captured, errors);\n if (Object.keys(errors).length) {\n if (changed) tell();\n if (!blur && captured === staged && identity === sessionIdentity() && sameRow(table.id, key)) {\n const first = Object.keys(errors)\n .map((name) => errorControl(captured, name))\n .find(Boolean);\n first?.focus();\n }\n return;\n }\n }\n feedback.delete(captured);\n const current = () => identity === sessionIdentity() && captured === staged && sameRow(table.id, key) && state.canWrite;\n const dispatchCurrent = () =>\n current() &&\n schema === state.schema &&\n generation === connectionGeneration() &&\n !draftSchemaChanged(table) &&\n (!app || (prefersPages() && canEditRow(currentTable, key))) &&\n (!blur || (navigation() && cancellation === autosaveCancellation && !captured.manualSaveRequired && !captured.needsReview));\n applying = true;\n if (blur) {\n autosaveIdentity = identity;\n autosaveOwner = { connection: connection ?? null, table: table.id, key: { ...key } };\n }\n try {\n tell();\n const ok = app || (await confirmUpdate(table, key, values, originals));\n if (!ok) return;\n if (!dispatchCurrent()) {\n if (!blur) toast(say('theRecordConnectionOrTable'), 'error');\n return;\n }\n /** @type {(() => void) | undefined} */\n let acknowledged;\n const result = await updateAttempts.run({ connection: connection ?? null, table: table.id, key }, values, () => {\n if (!dispatchCurrent()) throw Object.assign(new Error(say('theRecordChangedBefore')), { outcome: 'not_applied' });\n if (app) acknowledged = captureRecordWriteRefresh(table.id, key);\n return api('/api/update', { ...ownedBy(connection), table: table.id, key, values, expected: comparable(table, originals) });\n });\n if (result.kind !== 'applied') {\n if (result.kind === 'rejected') captured.manualSaveRequired = true;\n if (app && current() && result.kind === 'rejected') {\n /* The draft stays as it was; the fields the server named are marked\n on it, and nothing is retried — a blur save included. */\n const summary = markRefusal(captured, currentTable, result, !blur);\n if (summary) feedback.set(captured, { phase: 'error', message: summary });\n else feedback.delete(captured);\n tell();\n } else if (identity === sessionIdentity() && (result.kind !== 'uncertain' || !current())) toast(result.message, 'error');\n return;\n }\n const n = Object.keys(result.applied).length;\n const inputs = captured.inputs;\n // Settle the original draft even after navigation selected another record.\n for (const [column, value] of Object.entries(result.applied)) {\n if (Object.is(captured.values[column], values[column])) {\n delete captured.values[column];\n delete captured.originals[column];\n } else if (column in captured.values) captured.originals[column] = value;\n }\n // A row-defined field folded into a column that was written, unless it was edited again meanwhile.\n const foldedSaved = {};\n for (const name of Object.keys(staging)) {\n const fold = captured.folds?.[name];\n if (!fold || !Object.hasOwn(result.applied, fold.column)) continue;\n // Its editor is told what it now holds: the box's own text, which the object was written from.\n foldedSaved[name] = staging[name];\n if (!Object.is(captured.values[name], staging[name])) continue;\n delete captured.values[name];\n delete captured.originals[name];\n delete captured.folds[name];\n }\n if (!Object.keys(captured.values).length) {\n captured.needsReview = false;\n captured.manualSaveRequired = false;\n editErrors.delete(captured);\n }\n // What a refusal said was about the values it saw; these were written.\n clearServerErrors(captured);\n acknowledged?.();\n // History follows the original owner even if another record is now open.\n if (\n identity === sessionIdentity() &&\n connection === state.activeConnection &&\n schema === state.schema &&\n generation === connectionGeneration()\n )\n void shell().undo.refresh();\n tell();\n if (!current()) {\n if (identity === sessionIdentity())\n toast(say('updatedColumnsOnTheOriginal', { count: n, connection: connection ?? say('theOriginalConnection') }), 'ok');\n return;\n }\n\n // An App has no Undo: the dock says what was saved.\n if (app) feedback.set(captured, { phase: 'saved', message: say('changesSaved'), identity, columns: Object.keys(values) });\n else\n toast(\n say('updatedColumns', { count: n, name: table.name }),\n 'ok',\n !identity.tenantRequired && result.undoId\n ? {\n /* Beside the confirmation, because this is the moment someone realises\n it was the wrong row — and sending them to a menu to find Undo wastes\n the seconds in which they still remember what they changed. */\n label: say('common.undo'),\n run: () => {\n if (identity === sessionIdentity() && connection === state.activeConnection) void shell().undo.last(result.undoId);\n },\n }\n : undefined,\n );\n\n /* Confirmed in place rather than by re-rendering. A re-render would throw\n away the row you are looking at and rebuild it, which reads as a flicker\n and loses the caret; worse, it left the fields showing their unsaved\n styling because the DOM they styled was gone before the class was.\n Showing the saved value, in green, on the field you just edited is both\n calmer and more specific — it says *which* fields landed. */\n tell();\n confirmSaved(inputs, { ...result.applied, ...foldedSaved });\n // Only the pending bar is refreshed, so the green fields survive.\n onDone?.({ inPlace: true });\n } catch (err) {\n // Attempt failures are classified above; presentation failures must not resend.\n toast(err.message, 'error');\n } finally {\n if (blur) {\n autosaveIdentity = undefined;\n autosaveOwner = undefined;\n }\n applying = false;\n tell();\n }\n}\n\nfunction confirmSaved(inputs, applied) {\n for (const [column, value] of Object.entries(applied)) {\n const registered = inputs[column];\n const input = registered?.element;\n if (!input || !input.isConnected) continue;\n // The value the database actually stored, which may differ from what was\n // typed — \"17901\" comes back as the number 17901.\n registered.onCommitted?.(value);\n }\n}\n\n/** Show the statement before it runs. This is the last stop before a write. */\nfunction confirmUpdate(table, key, values, originals) {\n return new Promise((resolve) => {\n const q = (id) => `\"${id}\"`;\n const sets = Object.keys(values)\n .map((c) => `${q(c)} = ?`)\n .join(',\\n ');\n const where = [\n ...Object.keys(key).map((c) => `${q(c)} = ?`),\n ...Object.keys(originals).map((c) => `${q(c)} ${originals[c] === null ? 'IS NULL' : '= ?'}`),\n ].join(' AND ');\n const sql = `UPDATE ${q(table.id)}\\n SET ${sets}\\n WHERE ${where};`;\n\n /* The parameters shown are the raw staged values. The server coerces them\n against the declared column types and returns what it applied, so a\n number typed as text is corrected there rather than guessed at here. */\n const params = JSON.stringify([\n ...Object.values(values),\n ...Object.values(key),\n ...Object.values(originals).filter((value) => value !== null),\n ]);\n\n const rows = Object.entries(values).map(([column, to]) => {\n const from = originals[column];\n const type = table.columns.find((c) => c.name === column)?.type ?? '';\n return el('tr', {}, [\n el('td', {}, [el('span', { class: 'diff-col', text: column }), el('span', { class: 'diff-type', text: type.toLowerCase() })]),\n el('td', { class: `diff-from${from === null ? ' null' : ''}`, text: from === null ? 'null' : String(from) }),\n el('td', { class: 'diff-arrow', text: '→' }),\n el('td', { class: `diff-to${to === null ? ' null' : ''}`, text: to === null ? 'null' : String(to) }),\n ]);\n });\n\n const dialog = el('dialog', { class: 'confirm confirm-wide' }, [\n el('h2', { text: rows.length === 1 ? say('applyThisChange') : say('applyChanges', { count: rows.length }) }),\n el('p', {}, [\n document.createTextNode('One row in '),\n el('strong', { text: table.id }),\n document.createTextNode(', identified by '),\n el('strong', {\n text: Object.entries(key)\n .map(([k, v]) => `${k} = ${v}`)\n .join(', '),\n }),\n document.createTextNode('. Applied as a single statement only if these fields still match their original values.'),\n ]),\n el('table', { class: 'confirm-diff' }, el('tbody', {}, rows)),\n el('pre', { class: 'ddl', text: sql }),\n el('p', { class: 'confirm-params', text: say('parameters', { params }) }),\n el('div', { class: 'confirm-actions' }, [\n el('button', {\n type: 'button',\n class: 'ghost',\n text: say('common.cancel'),\n onclick: () => {\n dialog.close();\n resolve(false);\n },\n }),\n el('button', {\n type: 'button',\n class: 'primary',\n text: say('common.apply'),\n onclick: () => {\n dialog.close();\n resolve(true);\n },\n }),\n ]),\n ]);\n dialog.addEventListener('close', () => dialog.remove());\n dialog.addEventListener('cancel', () => resolve(false));\n portalRoot().append(dialog);\n dialog.showModal();\n });\n}\n\n/** Why a row is not editable, for the record view to explain rather than hide. */\nexport function whyNotEditable(table) {\n if (!state.canWrite) return null; // not in write mode: say nothing\n if (!table) return say('unknownTable');\n if (table.isView) return say('thisIsAView');\n if (!table.columns.some((c) => c.primaryKey)) {\n return say('thisTableHasNoPrimary');\n }\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { c as computedColumnMeta } from "./shared-poc11xxo.js";
|
|
|
2
2
|
import { A as isFlagColumn, D as columnKind, E as coerceForColumn } from "./shared-DJZjSi3J.js";
|
|
3
3
|
import { n as formShownFields, r as isRequired, t as autoKey } from "./shared-CoarExWh.js";
|
|
4
4
|
import { t as evaluateComputed } from "./shared-DtWgKxbD.js";
|
|
5
|
-
import { D as typedValue, w as evaluateFormCondition } from "./shared-
|
|
5
|
+
import { D as typedValue, w as evaluateFormCondition } from "./shared-CL3RLKDA.js";
|
|
6
6
|
// packages/kit/src/client/components/newRecordModel.ts
|
|
7
7
|
/** Unknown draft dependencies stay visible so an incomplete form never hides
|
|
8
8
|
* the control needed to resolve its own condition. */
|
|
@@ -200,4 +200,4 @@ function flagStart(column, defaults) {
|
|
|
200
200
|
}
|
|
201
201
|
export { formFrame as a, insertValues as c, narrowingCondition as d, presetValue as f, formColumns as i, isFormFieldVisible as l, fieldInput as n, formGroups as o, flagStart as r, hasFormChanges as s, clockDefault as t, missingFields as u };
|
|
202
202
|
|
|
203
|
-
//# sourceMappingURL=shared-
|
|
203
|
+
//# sourceMappingURL=shared-bAgeiRa5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-BnUptuUp.js","names":[],"sources":["../../../kit/src/client/components/newRecordModel.ts"],"sourcesContent":["import { coerceForColumn, columnKind, isFlagColumn, type ColumnMeta, type TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { autoKey, formShownFields, isRequired } from '@mistriwork/engine/shared/form.js';\nimport type { AppForm } from '@mistriwork/engine/shared/servedApp.js';\nimport { evaluateFormCondition, typedValue, type FormScalar } from '@mistriwork/engine/shared/formValues.js';\nimport { computedColumnMeta, type ComputedNode } from '@mistriwork/engine/shared/computed.js';\nimport { evaluateComputed } from '@mistriwork/engine/shared/computedValue.js';\n\n/** The client-side presentation subset of an authored App form. */\nexport type FormCuration = Omit<AppForm<string>, 'defaults'> & { defaults?: Record<string, unknown> };\n\ninterface FormGroup {\n label: string;\n columns: ColumnMeta[];\n}\n\n/** Unknown draft dependencies stay visible so an incomplete form never hides\n * the control needed to resolve its own condition. */\nexport function isFormFieldVisible(\n form: FormCuration | undefined,\n column: ColumnMeta,\n values: Readonly<Record<string, FormScalar | string>>,\n table: TableMeta,\n): boolean {\n const condition = form?.when?.[column.name];\n if (!condition) return true;\n try {\n /* A computed column the condition reads is worked out from the draft, as the record will compute it once\n stored: `when: { po_number: 'total > 1000' }`. One over a rollup reads no lines here, so it stays unknown. */\n const computed = Object.entries(table.computed ?? {});\n if (!computed.length) return evaluateFormCondition(condition, values, table.columns) !== false;\n const clock = { today: new Date().toISOString().slice(0, 10), now: new Date(), me: null };\n const worked = Object.fromEntries(\n computed.map(([name, value]) => {\n const result = evaluateComputed(value.expr as ComputedNode, clock, (path) => typedValue(table, path, values[path]));\n return [\n name,\n result !== null && typeof result === 'object' ? ('day' in result ? result.day : result.instant.toISOString()) : result,\n ];\n }),\n );\n const columns = [...table.columns, ...computed.map(([name, value]) => computedColumnMeta(name, value))];\n return evaluateFormCondition(condition, { ...values, ...worked }, columns) !== false;\n } catch {\n // A server-validated form should never reach this branch, but rendering\n // must fail open if a stale app response crosses a client reload.\n return true;\n }\n}\n\nfunction editableColumns(table: TableMeta, app: boolean): ColumnMeta[] {\n const assigned = app ? autoKey(table) : null;\n // A machine's column starts in its first state and then moves only by its verbs.\n return table.columns.filter(\n (c) => c.writable !== false && c.changesBy !== 'actions' && c.identity !== 'always' && !(app && c.identity) && c.name !== assigned,\n );\n}\n\nexport function formColumns(table: TableMeta, form: FormCuration | undefined, app: boolean): ColumnMeta[] {\n const shown = formShownFields(form);\n const columns = shown ? [...new Set(shown)].flatMap((name) => table.columns.find((c) => c.name === name) ?? []) : table.columns;\n const editable = new Set(editableColumns(table, app));\n return columns.filter((c) => editable.has(c));\n}\n\n/** Grouped fields retain authored order; ungrouped fields follow in form order. */\nexport function formGroups(table: TableMeta, form: FormCuration | undefined, app: boolean): FormGroup[] {\n const columns = formColumns(table, form, app);\n if (!form?.groups?.length) return [{ label: '', columns }];\n const byName = new Map(columns.map((column) => [column.name, column]));\n const claimed = new Set<string>();\n const groups = form.groups.flatMap((group) => {\n const groupColumns = group.fields.flatMap((name) => {\n const column = byName.get(name);\n if (!column || claimed.has(name)) return [];\n claimed.add(name);\n return [column];\n });\n return groupColumns.length ? [{ label: group.label, columns: groupColumns }] : [];\n });\n const remainder = columns.filter((column) => !claimed.has(column.name));\n if (remainder.length) groups.push({ label: '', columns: remainder });\n return groups.length ? groups : [{ label: '', columns }];\n}\n\nexport function presetValue(column: ColumnMeta, defaults: Record<string, unknown>): string {\n const value = Object.hasOwn(defaults, column.name) ? defaults[column.name] : undefined;\n if (value === null || value === undefined) return '';\n if (!column.allowed?.length && isFlagColumn(column)) {\n const flag = typeof value === 'string' ? coerceForColumn(column.type, value) : value;\n if (typeof flag === 'boolean') return flag ? '1' : '0';\n }\n return String(value);\n}\n\n/** Returning to a displayed preset is clean, except when clearing means omission. */\nexport function hasFormChanges(\n columns: ColumnMeta[],\n values: Record<string, string>,\n defaults: Record<string, unknown>,\n edited: ReadonlySet<string>,\n): boolean {\n return columns.some((column) => {\n if (!edited.has(column.name)) return false;\n const value = values[column.name] ?? '';\n return (\n value !== presetValue(column, defaults) ||\n (value === '' && Object.hasOwn(defaults, column.name) && defaults[column.name] !== undefined)\n );\n });\n}\n\n/** Untouched DSL defaults retain their types; a cleared, edited control means omission. */\nexport function insertValues(\n values: Record<string, string>,\n defaults: Record<string, unknown>,\n edited: ReadonlySet<string>,\n columns: readonly ColumnMeta[],\n): Record<string, unknown> {\n const entries = new Map(Object.entries(defaults).filter(([, value]) => value !== undefined));\n for (const [name, value] of Object.entries(values)) {\n if (!edited.has(name) && entries.has(name)) continue;\n entries.delete(name);\n if (value !== '') entries.set(name, value);\n }\n // Curation may hide allowed defaults, but cannot restore fields omitted or\n // made read-only by the server. Also removes stale values from an open form.\n const writable = new Set(columns.filter((column) => column.writable !== false).map((column) => column.name));\n return Object.fromEntries([...entries].filter(([name]) => writable.has(name)));\n}\n\n/**\n * The required columns a create leaves without a value. `derived` is the form's values taken from a referenced\n * record (`{ from: 'part_id.unit_price' }`), for columns the form does not show: the server fills one from the\n * record its reference names (server app/appValidation.ts fillDerived), so it is not missing while that\n * reference has a value. A shown one the person emptied is theirs to fill, and is not passed here.\n */\nexport function missingFields(\n columns: ColumnMeta[],\n values: Record<string, unknown>,\n assigned: string | null,\n derived?: Readonly<Record<string, string | undefined>>,\n): ColumnMeta[] {\n return columns.filter((column) => {\n if (column.writable === false) return false;\n const present = Object.hasOwn(values, column.name) && values[column.name] !== undefined;\n if (present) return !column.nullable && values[column.name] === null;\n const via = derived?.[column.name]?.split('.')[0];\n if (via && values[via] !== undefined && values[via] !== null && values[via] !== '') return false;\n return isRequired(column, assigned);\n });\n}\n\n/* ---------- an App's New form: its frame, its inputs, its starting words ---------- */\n\n/** A drawer holds a short form beside the list; past this many fields, or with steps, the form is a page of its own. */\nconst DRAWER_FIELDS = 8;\n\n/** Where the New form is drawn: what it says, else a drawer for a short form and a page for a long or stepped one. */\nexport function formFrame(form: FormCuration | undefined, fieldCount: number): 'drawer' | 'page' {\n if (form?.open) return form.open;\n return form?.steps?.length || fieldCount > DRAWER_FIELDS ? 'page' : 'drawer';\n}\n\nexport type FieldInput =\n | 'text'\n | 'textarea'\n | 'richText'\n | 'number'\n | 'money'\n | 'radios'\n | 'listbox'\n | 'switch'\n | 'flag'\n | 'date'\n | 'datetime'\n | 'reference';\n\n/* A text column holding prose rather than a name or a code: said by its name,\n since a TEXT or `text` type says nothing of its length. */\nconst PROSE =\n /^(?:description|notes?|body|bio|biography|comments?|summary|details|message|instructions|remarks|content|about)$|_(?:notes?|description|details|comments?|summary)$/i;\n/** Radios show every word at once; past this many the listbox is shorter. The command form's rule. */\nconst RADIO_WORDS = 4;\n\n/** The declared length of a text column, when its type says one: `varchar(500)` → 500. */\nfunction declaredLength(column: ColumnMeta): number | undefined {\n const match = /\\(\\s*(\\d+)\\s*\\)/.exec(column.type);\n return match ? Number(match[1]) : undefined;\n}\n\n/** Whether a text column is drawn as a box of several lines. */\nfunction isMultiline(column: ColumnMeta, multiline?: boolean): boolean {\n if (multiline !== undefined) return multiline;\n if (column.allowed?.length || columnKind(column.type) !== 'text') return false;\n const length = declaredLength(column);\n if (length !== undefined) return length > 255;\n return /^(?:mediumtext|longtext|clob|ntext)$/i.test(column.type.trim()) || PROSE.test(column.name);\n}\n\n/**\n * The input an App's New form draws a column as, from the column and how the\n * App dresses it. `hasStart` is whether the field starts with a value (a form\n * default, or the database's): a vocabulary or a flag that must be answered\n * and has none to start from stays a listbox, whose empty entry says so.\n */\nexport function fieldInput(\n column: ColumnMeta,\n options: { money?: boolean; multiline?: boolean; richText?: boolean; required: boolean; hasStart: boolean; reference: boolean },\n): FieldInput {\n if (column.allowed?.length) return column.allowed.length <= RADIO_WORDS && (options.required || options.hasStart) ? 'radios' : 'listbox';\n const kind = columnKind(column.type);\n /* A declared boolean, or an integer a CHECK pins to 0 and 1: both are yes or no. */\n if (isFlagColumn(column)) return options.hasStart ? 'switch' : 'flag';\n if (options.reference) return 'reference';\n if (kind === 'date') return /time/i.test(column.type) ? 'datetime' : 'date';\n if (kind === 'number') return options.money ? 'money' : 'number';\n if (options.richText) return 'richText';\n return isMultiline(column, options.multiline) ? 'textarea' : 'text';\n}\n\n/** What a form default's word starts as, now: `today` a date, `now` a wall-clock time (or a date on a date column), said as the date field says one: `YYYY-MM-DD HH:MM`. */\nexport function clockDefault(word: 'today' | 'now', column: ColumnMeta, now: Date, timeZone?: string): string {\n const parts = Object.fromEntries(\n new Intl.DateTimeFormat('en-CA', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n hourCycle: 'h23',\n })\n .formatToParts(now)\n .map((part) => [part.type, part.value]),\n );\n const date = `${parts.year}-${parts.month}-${parts.day}`;\n return word === 'now' && /time/i.test(column.type) ? `${date} ${parts.hour}:${parts.minute}` : date;\n}\n\n/** The choices a narrowed reference offers, in the query language: `project_id = 4`; undefined while a field it reads is empty. */\nexport function narrowingCondition(\n where: Readonly<Record<string, string>> | undefined,\n values: Readonly<Record<string, unknown>>,\n): string | undefined {\n if (!where) return '';\n const clauses: string[] = [];\n for (const [remote, local] of Object.entries(where)) {\n const value = values[local];\n if (value === undefined || value === null || value === '') return undefined;\n // A key typed as text (\"4\") is still a number to the column; a word is quoted, so `me` or `today` is never read as one.\n const text = String(value);\n clauses.push(`${remote} = ${typeof value !== 'string' || /^-?\\d+(?:\\.\\d+)?$/.test(text) ? text : JSON.stringify(text)}`);\n }\n return clauses.join(' and ');\n}\n\n/**\n * Where a flag's switch starts: the form's default, else the database's when\n * it is a plain true or false, else off for a flag that must be answered. A\n * nullable flag with nothing to start from has none, and keeps the listbox\n * whose empty entry means \"leave it\".\n */\nexport function flagStart(column: ColumnMeta, defaults: Record<string, unknown>): boolean | undefined {\n if (Object.hasOwn(defaults, column.name)) {\n const value = defaults[column.name];\n const flag = typeof value === 'string' ? coerceForColumn(column.type, value) : value;\n if (typeof flag === 'boolean') return flag;\n /* An integer flag's default, said either way: 1, '1', true, 'true'. */\n const said = String(value).trim().toLowerCase();\n return /^(?:1|true|t)$/.test(said) ? true : /^(?:0|false|f)$/.test(said) ? false : undefined;\n }\n const stored = String(column.default ?? '')\n .replace(/^'(.*)'$/, '$1')\n .trim()\n .toLowerCase();\n if (/^(?:1|true|t)$/.test(stored)) return true;\n if (/^(?:0|false|f)$/.test(stored)) return false;\n return column.default === undefined && column.hasDefault !== true && !column.nullable ? false : undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-bAgeiRa5.js","names":[],"sources":["../../../kit/src/client/components/newRecordModel.ts"],"sourcesContent":["import { coerceForColumn, columnKind, isFlagColumn, type ColumnMeta, type TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { autoKey, formShownFields, isRequired } from '@mistriwork/engine/shared/form.js';\nimport type { AppForm } from '@mistriwork/engine/shared/servedApp.js';\nimport { evaluateFormCondition, typedValue, type FormScalar } from '@mistriwork/engine/shared/formValues.js';\nimport { computedColumnMeta, type ComputedNode } from '@mistriwork/engine/shared/computed.js';\nimport { evaluateComputed } from '@mistriwork/engine/shared/computedValue.js';\n\n/** The client-side presentation subset of an authored App form. */\nexport type FormCuration = Omit<AppForm<string>, 'defaults'> & { defaults?: Record<string, unknown> };\n\ninterface FormGroup {\n label: string;\n columns: ColumnMeta[];\n}\n\n/** Unknown draft dependencies stay visible so an incomplete form never hides\n * the control needed to resolve its own condition. */\nexport function isFormFieldVisible(\n form: FormCuration | undefined,\n column: ColumnMeta,\n values: Readonly<Record<string, FormScalar | string>>,\n table: TableMeta,\n): boolean {\n const condition = form?.when?.[column.name];\n if (!condition) return true;\n try {\n /* A computed column the condition reads is worked out from the draft, as the record will compute it once\n stored: `when: { po_number: 'total > 1000' }`. One over a rollup reads no lines here, so it stays unknown. */\n const computed = Object.entries(table.computed ?? {});\n if (!computed.length) return evaluateFormCondition(condition, values, table.columns) !== false;\n const clock = { today: new Date().toISOString().slice(0, 10), now: new Date(), me: null };\n const worked = Object.fromEntries(\n computed.map(([name, value]) => {\n const result = evaluateComputed(value.expr as ComputedNode, clock, (path) => typedValue(table, path, values[path]));\n return [\n name,\n result !== null && typeof result === 'object' ? ('day' in result ? result.day : result.instant.toISOString()) : result,\n ];\n }),\n );\n const columns = [...table.columns, ...computed.map(([name, value]) => computedColumnMeta(name, value))];\n return evaluateFormCondition(condition, { ...values, ...worked }, columns) !== false;\n } catch {\n // A server-validated form should never reach this branch, but rendering\n // must fail open if a stale app response crosses a client reload.\n return true;\n }\n}\n\nfunction editableColumns(table: TableMeta, app: boolean): ColumnMeta[] {\n const assigned = app ? autoKey(table) : null;\n // A machine's column starts in its first state and then moves only by its verbs.\n return table.columns.filter(\n (c) => c.writable !== false && c.changesBy !== 'actions' && c.identity !== 'always' && !(app && c.identity) && c.name !== assigned,\n );\n}\n\nexport function formColumns(table: TableMeta, form: FormCuration | undefined, app: boolean): ColumnMeta[] {\n const shown = formShownFields(form);\n const columns = shown ? [...new Set(shown)].flatMap((name) => table.columns.find((c) => c.name === name) ?? []) : table.columns;\n const editable = new Set(editableColumns(table, app));\n return columns.filter((c) => editable.has(c));\n}\n\n/** Grouped fields retain authored order; ungrouped fields follow in form order. */\nexport function formGroups(table: TableMeta, form: FormCuration | undefined, app: boolean): FormGroup[] {\n const columns = formColumns(table, form, app);\n if (!form?.groups?.length) return [{ label: '', columns }];\n const byName = new Map(columns.map((column) => [column.name, column]));\n const claimed = new Set<string>();\n const groups = form.groups.flatMap((group) => {\n const groupColumns = group.fields.flatMap((name) => {\n const column = byName.get(name);\n if (!column || claimed.has(name)) return [];\n claimed.add(name);\n return [column];\n });\n return groupColumns.length ? [{ label: group.label, columns: groupColumns }] : [];\n });\n const remainder = columns.filter((column) => !claimed.has(column.name));\n if (remainder.length) groups.push({ label: '', columns: remainder });\n return groups.length ? groups : [{ label: '', columns }];\n}\n\nexport function presetValue(column: ColumnMeta, defaults: Record<string, unknown>): string {\n const value = Object.hasOwn(defaults, column.name) ? defaults[column.name] : undefined;\n if (value === null || value === undefined) return '';\n if (!column.allowed?.length && isFlagColumn(column)) {\n const flag = typeof value === 'string' ? coerceForColumn(column.type, value) : value;\n if (typeof flag === 'boolean') return flag ? '1' : '0';\n }\n return String(value);\n}\n\n/** Returning to a displayed preset is clean, except when clearing means omission. */\nexport function hasFormChanges(\n columns: ColumnMeta[],\n values: Record<string, string>,\n defaults: Record<string, unknown>,\n edited: ReadonlySet<string>,\n): boolean {\n return columns.some((column) => {\n if (!edited.has(column.name)) return false;\n const value = values[column.name] ?? '';\n return (\n value !== presetValue(column, defaults) ||\n (value === '' && Object.hasOwn(defaults, column.name) && defaults[column.name] !== undefined)\n );\n });\n}\n\n/** Untouched DSL defaults retain their types; a cleared, edited control means omission. */\nexport function insertValues(\n values: Record<string, string>,\n defaults: Record<string, unknown>,\n edited: ReadonlySet<string>,\n columns: readonly ColumnMeta[],\n): Record<string, unknown> {\n const entries = new Map(Object.entries(defaults).filter(([, value]) => value !== undefined));\n for (const [name, value] of Object.entries(values)) {\n if (!edited.has(name) && entries.has(name)) continue;\n entries.delete(name);\n if (value !== '') entries.set(name, value);\n }\n // Curation may hide allowed defaults, but cannot restore fields omitted or\n // made read-only by the server. Also removes stale values from an open form.\n const writable = new Set(columns.filter((column) => column.writable !== false).map((column) => column.name));\n return Object.fromEntries([...entries].filter(([name]) => writable.has(name)));\n}\n\n/**\n * The required columns a create leaves without a value. `derived` is the form's values taken from a referenced\n * record (`{ from: 'part_id.unit_price' }`), for columns the form does not show: the server fills one from the\n * record its reference names (server app/appValidation.ts fillDerived), so it is not missing while that\n * reference has a value. A shown one the person emptied is theirs to fill, and is not passed here.\n */\nexport function missingFields(\n columns: ColumnMeta[],\n values: Record<string, unknown>,\n assigned: string | null,\n derived?: Readonly<Record<string, string | undefined>>,\n): ColumnMeta[] {\n return columns.filter((column) => {\n if (column.writable === false) return false;\n const present = Object.hasOwn(values, column.name) && values[column.name] !== undefined;\n if (present) return !column.nullable && values[column.name] === null;\n const via = derived?.[column.name]?.split('.')[0];\n if (via && values[via] !== undefined && values[via] !== null && values[via] !== '') return false;\n return isRequired(column, assigned);\n });\n}\n\n/* ---------- an App's New form: its frame, its inputs, its starting words ---------- */\n\n/** A drawer holds a short form beside the list; past this many fields, or with steps, the form is a page of its own. */\nconst DRAWER_FIELDS = 8;\n\n/** Where the New form is drawn: what it says, else a drawer for a short form and a page for a long or stepped one. */\nexport function formFrame(form: FormCuration | undefined, fieldCount: number): 'drawer' | 'page' {\n if (form?.open) return form.open;\n return form?.steps?.length || fieldCount > DRAWER_FIELDS ? 'page' : 'drawer';\n}\n\nexport type FieldInput =\n | 'text'\n | 'textarea'\n | 'richText'\n | 'number'\n | 'money'\n | 'radios'\n | 'listbox'\n | 'switch'\n | 'flag'\n | 'date'\n | 'datetime'\n | 'reference';\n\n/* A text column holding prose rather than a name or a code: said by its name,\n since a TEXT or `text` type says nothing of its length. */\nconst PROSE =\n /^(?:description|notes?|body|bio|biography|comments?|summary|details|message|instructions|remarks|content|about)$|_(?:notes?|description|details|comments?|summary)$/i;\n/** Radios show every word at once; past this many the listbox is shorter. The command form's rule. */\nconst RADIO_WORDS = 4;\n\n/** The declared length of a text column, when its type says one: `varchar(500)` → 500. */\nfunction declaredLength(column: ColumnMeta): number | undefined {\n const match = /\\(\\s*(\\d+)\\s*\\)/.exec(column.type);\n return match ? Number(match[1]) : undefined;\n}\n\n/** Whether a text column is drawn as a box of several lines. */\nfunction isMultiline(column: ColumnMeta, multiline?: boolean): boolean {\n if (multiline !== undefined) return multiline;\n if (column.allowed?.length || columnKind(column.type) !== 'text') return false;\n const length = declaredLength(column);\n if (length !== undefined) return length > 255;\n return /^(?:mediumtext|longtext|clob|ntext)$/i.test(column.type.trim()) || PROSE.test(column.name);\n}\n\n/**\n * The input an App's New form draws a column as, from the column and how the\n * App dresses it. `hasStart` is whether the field starts with a value (a form\n * default, or the database's): a vocabulary or a flag that must be answered\n * and has none to start from stays a listbox, whose empty entry says so.\n */\nexport function fieldInput(\n column: ColumnMeta,\n options: { money?: boolean; multiline?: boolean; richText?: boolean; required: boolean; hasStart: boolean; reference: boolean },\n): FieldInput {\n if (column.allowed?.length) return column.allowed.length <= RADIO_WORDS && (options.required || options.hasStart) ? 'radios' : 'listbox';\n const kind = columnKind(column.type);\n /* A declared boolean, or an integer a CHECK pins to 0 and 1: both are yes or no. */\n if (isFlagColumn(column)) return options.hasStart ? 'switch' : 'flag';\n if (options.reference) return 'reference';\n if (kind === 'date') return /time/i.test(column.type) ? 'datetime' : 'date';\n if (kind === 'number') return options.money ? 'money' : 'number';\n if (options.richText) return 'richText';\n return isMultiline(column, options.multiline) ? 'textarea' : 'text';\n}\n\n/** What a form default's word starts as, now: `today` a date, `now` a wall-clock time (or a date on a date column), said as the date field says one: `YYYY-MM-DD HH:MM`. */\nexport function clockDefault(word: 'today' | 'now', column: ColumnMeta, now: Date, timeZone?: string): string {\n const parts = Object.fromEntries(\n new Intl.DateTimeFormat('en-CA', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n hourCycle: 'h23',\n })\n .formatToParts(now)\n .map((part) => [part.type, part.value]),\n );\n const date = `${parts.year}-${parts.month}-${parts.day}`;\n return word === 'now' && /time/i.test(column.type) ? `${date} ${parts.hour}:${parts.minute}` : date;\n}\n\n/** The choices a narrowed reference offers, in the query language: `project_id = 4`; undefined while a field it reads is empty. */\nexport function narrowingCondition(\n where: Readonly<Record<string, string>> | undefined,\n values: Readonly<Record<string, unknown>>,\n): string | undefined {\n if (!where) return '';\n const clauses: string[] = [];\n for (const [remote, local] of Object.entries(where)) {\n const value = values[local];\n if (value === undefined || value === null || value === '') return undefined;\n // A key typed as text (\"4\") is still a number to the column; a word is quoted, so `me` or `today` is never read as one.\n const text = String(value);\n clauses.push(`${remote} = ${typeof value !== 'string' || /^-?\\d+(?:\\.\\d+)?$/.test(text) ? text : JSON.stringify(text)}`);\n }\n return clauses.join(' and ');\n}\n\n/**\n * Where a flag's switch starts: the form's default, else the database's when\n * it is a plain true or false, else off for a flag that must be answered. A\n * nullable flag with nothing to start from has none, and keeps the listbox\n * whose empty entry means \"leave it\".\n */\nexport function flagStart(column: ColumnMeta, defaults: Record<string, unknown>): boolean | undefined {\n if (Object.hasOwn(defaults, column.name)) {\n const value = defaults[column.name];\n const flag = typeof value === 'string' ? coerceForColumn(column.type, value) : value;\n if (typeof flag === 'boolean') return flag;\n /* An integer flag's default, said either way: 1, '1', true, 'true'. */\n const said = String(value).trim().toLowerCase();\n return /^(?:1|true|t)$/.test(said) ? true : /^(?:0|false|f)$/.test(said) ? false : undefined;\n }\n const stored = String(column.default ?? '')\n .replace(/^'(.*)'$/, '$1')\n .trim()\n .toLowerCase();\n if (/^(?:1|true|t)$/.test(stored)) return true;\n if (/^(?:0|false|f)$/.test(stored)) return false;\n return column.default === undefined && column.hasDefault !== true && !column.nullable ? false : undefined;\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { it as useQuery } from "./shared-poc11xxo.js";
|
|
2
2
|
import { ut as humanName } from "./shared-DJZjSi3J.js";
|
|
3
|
-
import { L as state, d as findTable, i as api, st as ownedBy } from "./shared-
|
|
4
|
-
import { f as Value } from "./shared-
|
|
3
|
+
import { L as state, d as findTable, i as api, st as ownedBy } from "./shared-BoLbc2WD.js";
|
|
4
|
+
import { f as Value } from "./shared-Chp88all.js";
|
|
5
5
|
import { a as definitionFilter, i as definitionColumns, n as definedFromInput, o as readDefinitions, r as definedObject } from "./shared-BjCz2A6c.js";
|
|
6
|
-
import { t as Editable } from "./shared-
|
|
7
|
-
import { n as fieldInput } from "./shared-
|
|
6
|
+
import { t as Editable } from "./shared-BumxsBlA.js";
|
|
7
|
+
import { n as fieldInput } from "./shared-bAgeiRa5.js";
|
|
8
8
|
import { useEffect, useMemo, useState } from "react";
|
|
9
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
// packages/kit/src/client/components/DefinedFields.tsx
|
|
@@ -281,4 +281,4 @@ function DefinedBoxes({ column, binding, per, onBoxes }) {
|
|
|
281
281
|
}
|
|
282
282
|
export { DefinedBoxes, DefinedFields, DefinedInputs };
|
|
283
283
|
|
|
284
|
-
//# sourceMappingURL=shared-
|
|
284
|
+
//# sourceMappingURL=shared-cgXG7OgZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-BxMvSjey.js","names":["_Fragment"],"sources":["../../../kit/src/client/components/DefinedFields.tsx"],"sourcesContent":["/**\n * Row-defined fields (`resources.<r>.defined`, shared/definedFields.ts): a\n * JSON column whose keys an admin defines as rows. Drawn as the record's own\n * fields — the same captions, the same editor, the same Save — on the record\n * page (DefinedFields), as the New form's fields (DefinedInputs), and as a\n * list's refinements (DefinedBoxes).\n *\n * The definitions are read like any of the reader's rows (`/api/query`, routed\n * to the tenant by core.js), so the fields a record is shown with are the ones\n * the server will hold its write to. Loaded on demand (onDemand.tsx): an App\n * without a bound column never fetches this.\n */\nimport { useQuery } from '@tanstack/react-query';\nimport { useEffect, useMemo, useState, type ReactNode } from 'react';\nimport { api, findTable, state } from '../core.js';\nimport { ownedBy } from '../requestIdentity.js';\nimport { humanName } from '@mistriwork/engine/shared/model.js';\nimport { DEFINITIONS_MOST, type DefinedBinding, type DefinedField } from '@mistriwork/engine/shared/definedFields.js';\nimport {\n definedFromInput,\n definedObject,\n definitionColumns,\n definitionFilter,\n readDefinitions,\n} from '@mistriwork/engine/shared/definedValues.js';\nimport type { ColumnMeta, TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport type { DefinedFold } from '../recordDrafts.js';\nimport { Editable } from './Editable.js';\nimport { Value } from './Value.js';\nimport type { PlatformControl } from './NewRecord.js';\nimport { fieldInput } from './newRecordModel.js';\nimport type { Box } from './FilterBoxes.js';\n\n/** The fields a record of this `per` value has, in their order; a definitions table this reader cannot read has none. */\nfunction useDefinitions(binding: DefinedBinding, per: unknown, connection?: string) {\n const from = findTable(binding.from) as TableMeta | undefined;\n const owner = connection || (state.activeConnection as string | null) || '';\n const scoped = binding.per ? (per === undefined || per === null || per === '' ? null : String(per)) : null;\n return useQuery({\n queryKey: ['defined-fields', owner, binding.from, binding.per ?? '', scoped],\n enabled: Boolean(from),\n staleTime: 30_000,\n queryFn: async () => {\n const filter = definitionFilter(binding.per, per);\n const data = (await api('/api/query', {\n ...ownedBy(owner),\n table: from!.id,\n columns: definitionColumns(from!, binding.per),\n ...(filter ? { filter } : {}),\n limit: DEFINITIONS_MOST,\n offset: 0,\n })) as { rows?: Record<string, unknown>[] };\n return readDefinitions(data.rows ?? [], binding.per);\n },\n });\n}\n\nconst TYPES: Record<DefinedField['type'], string> = {\n text: 'text',\n textarea: 'text',\n number: 'numeric',\n money: 'numeric',\n date: 'date',\n datetime: 'timestamp',\n bool: 'boolean',\n choice: 'text',\n choices: 'text',\n};\n\n/** A field as a column the platform's controls draw: `specs.capacity`, of the type its definition names. */\nfunction fieldColumn(column: string, field: DefinedField): ColumnMeta & { allowed?: string[] } {\n return {\n name: `${column}.${field.key}`,\n type: TYPES[field.type],\n nullable: true,\n primaryKey: false,\n ...(field.type === 'choice' && field.options.length ? { allowed: field.options } : {}),\n };\n}\n\n/** A value as a box holds it: a list as its choices with commas, a yes or no as the flag controls spell it. */\nfunction boxText(field: DefinedField, value: unknown): string | null {\n if (value === undefined || value === null) return null;\n if (Array.isArray(value)) return value.join(', ');\n if (field.type === 'bool' && typeof value === 'boolean') return value ? '1' : '0';\n return String(value);\n}\n\n/** What a page shows for a value: a list said with commas, a yes or no as a flag column says one. */\nconst shownValue = (field: DefinedField, value: unknown) =>\n Array.isArray(value) ? value.join(', ') : field.type === 'bool' && typeof value === 'boolean' ? (value ? 1 : 0) : value;\n\n/** The keys an object holds, as fields to show where no definition can be read: said, never edited. */\nconst keysOf = (object: Record<string, unknown>): DefinedField[] =>\n Object.keys(object).map((key) => ({ key, label: humanName(key), type: 'text', options: [], required: false }));\n\n/** The record page: one `page-field` per definition, in the section's own list, editable where the record is. */\nexport function DefinedFields({\n base,\n row,\n column,\n binding,\n recordKey,\n editing,\n onSaved,\n isCurrent,\n connection,\n}: {\n base: TableMeta;\n row: Record<string, unknown>;\n column: string;\n binding: DefinedBinding;\n recordKey: Record<string, unknown>;\n editing: boolean;\n onSaved?: (opts?: { inPlace?: boolean }) => void;\n isCurrent?: () => boolean;\n connection?: string;\n}) {\n const definitions = useDefinitions(binding, binding.per ? row[binding.per] : undefined, connection);\n const object = useMemo(() => definedObject(row[column]) ?? {}, [row, column]);\n // One row per draw, so an editor's \"this is what was saved\" stays with the row it was read from.\n const fieldRow = useMemo(() => {\n const shown: Record<string, unknown> = { ...row };\n for (const field of definitions.data ?? []) shown[`${column}.${field.key}`] = boxText(field, object[field.key]);\n return shown;\n }, [row, column, object, definitions.data]);\n if (definitions.isPending && definitions.fetchStatus !== 'idle') return null;\n const read = definitions.data !== undefined;\n const fields = read ? definitions.data : keysOf(object);\n return (\n <>\n {fields.map((field) => {\n const meta = fieldColumn(column, field);\n const value = object[field.key];\n let dd: ReactNode;\n if (editing && read) {\n const defined: DefinedFold = { column, label: field.label, object, toValue: (text) => definedFromInput(field, text) };\n dd = (\n <dd className=\"page-field-edit\">\n <Editable\n table={base}\n row={fieldRow}\n column={{ ...meta, defined } as ColumnMeta}\n recordKey={recordKey}\n onSaved={onSaved}\n isCurrent={isCurrent}\n app\n display={(next) => <Value col={meta} value={next === null ? null : shownValue(field, definedFromInput(field, next))} />}\n />\n </dd>\n );\n } else if (value === undefined || value === null || value === '') {\n dd = (\n <dd className=\"null\" title=\"null\">\n —\n </dd>\n );\n } else {\n dd = (\n <dd>\n <Value col={meta} value={shownValue(field, value)} />\n </dd>\n );\n }\n return (\n <div key={field.key} className=\"page-field\">\n <dt title={field.help ?? meta.name}>{field.label}</dt>\n {dd}\n </div>\n );\n })}\n </>\n );\n}\n\n/**\n * The New form: one field per definition the chosen `per` value picks, drawn\n * with the form's own controls; the object travels as the column's JSON text.\n * A refusal naming `specs.capacity` is said under that field.\n */\nexport function DefinedInputs({\n column,\n binding,\n per,\n value,\n onChange,\n errors,\n connection,\n Control,\n}: {\n column: string;\n binding: DefinedBinding;\n per: unknown;\n /** The New form's own control, handed in (NewRecord.tsx loads this module, so it cannot import it back). */\n Control: typeof PlatformControl;\n value: string;\n onChange: (text: string) => void;\n errors: readonly { field: string; message: string }[];\n connection?: string;\n}) {\n const definitions = useDefinitions(binding, per, connection);\n const object = definedObject(value) ?? {};\n const [boxes, setBoxes] = useState<Record<string, string>>({});\n const set = (field: DefinedField, text: string) => {\n setBoxes((previous) => ({ ...previous, [field.key]: text }));\n const next = { ...object };\n const typed = definedFromInput(field, text);\n if (typed === undefined) delete next[field.key];\n else next[field.key] = typed;\n onChange(JSON.stringify(next));\n };\n return (\n <>\n {(definitions.data ?? []).map((field) => {\n const meta = fieldColumn(column, field);\n const name = meta.name;\n const error = errors.find((candidate) => candidate.field === name)?.message;\n const errorId = `${name}-error`;\n const helpId = field.help ? `${name}-help` : undefined;\n const text = Object.hasOwn(boxes, field.key) ? boxes[field.key] : (boxText(field, object[field.key]) ?? '');\n const kind = fieldInput(meta, {\n required: field.required,\n hasStart: false,\n reference: false,\n multiline: field.type === 'textarea',\n money: field.type === 'money',\n });\n return (\n <div key={field.key} className={`insert-field form-field${error ? ' missing is-invalid' : ''}`}>\n <label className=\"form-field-label\">\n {field.label}\n {field.required && <span className=\"req\">*</span>}\n </label>\n {field.type === 'choices' ? (\n <div className=\"command-choices insert-choices\" role=\"group\" aria-label={field.label}>\n {field.options.map((option) => {\n const chosen = text.split(',').map((item) => item.trim());\n return (\n <label className=\"command-choice\" key={option}>\n <input\n type=\"checkbox\"\n checked={chosen.includes(option)}\n onChange={(event) =>\n set(\n field,\n field.options.filter((item) => (item === option ? event.target.checked : chosen.includes(item))).join(', '),\n )\n }\n />\n {option}\n </label>\n );\n })}\n </div>\n ) : (\n <Control\n column={meta}\n app\n required={field.required}\n assigned={null}\n spoken={field.label}\n target={() => undefined}\n value={text}\n kind={kind}\n onChange={(next) => set(field, next)}\n register={() => {}}\n explicitNull={false}\n errorId={error ? errorId : undefined}\n helpId={helpId}\n />\n )}\n {field.help && (\n <p id={helpId} className=\"form-field-hint\">\n {field.help}\n </p>\n )}\n <span id={errorId} className=\"insert-missing\" aria-live=\"polite\" hidden={!error}>\n {error}\n </span>\n </div>\n );\n })}\n </>\n );\n}\n\n/* The facet a field is asked with: a choice is a checklist of its options, a\n yes or no a toggle, a list of choices its options asked with `has`, a\n number what its values are (a range or a short list); text and a date are\n a box. */\nconst BOX_KINDS: Record<DefinedField['type'], Box['kind']> = {\n text: 'text',\n textarea: 'text',\n number: 'text',\n money: 'text',\n date: 'text',\n datetime: 'text',\n bool: 'flag',\n choice: 'enum',\n choices: 'tags',\n};\n\n/**\n * A list's refinements: a bound column in a view's `filters` stands for one\n * box per field, handed to the list (AppList.tsx), which draws them as it\n * draws any — the rail's facets, the bar's pickers, chips that say their\n * labels. The fields are those of the list's `per` where it asks one value\n * (`category_id = 3`), and every field otherwise.\n */\nexport function DefinedBoxes({\n column,\n binding,\n per,\n onBoxes,\n}: {\n column: string;\n binding: DefinedBinding;\n per: string | undefined;\n onBoxes: (column: string, boxes: Box[]) => void;\n}) {\n const definitions = useDefinitions(per === undefined ? { from: binding.from } : binding, per);\n useEffect(() => {\n if (!definitions.data) return;\n onBoxes(\n column,\n definitions.data.map((field) => {\n const meta = { ...fieldColumn(column, field), ...(field.type === 'choices' ? { allowed: field.options } : {}) };\n return { column: meta.name, label: field.label, kind: BOX_KINDS[field.type], meta };\n }),\n );\n }, [definitions.data]); // eslint-disable-line react-hooks/exhaustive-deps\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-cgXG7OgZ.js","names":["_Fragment"],"sources":["../../../kit/src/client/components/DefinedFields.tsx"],"sourcesContent":["/**\n * Row-defined fields (`resources.<r>.defined`, shared/definedFields.ts): a\n * JSON column whose keys an admin defines as rows. Drawn as the record's own\n * fields — the same captions, the same editor, the same Save — on the record\n * page (DefinedFields), as the New form's fields (DefinedInputs), and as a\n * list's refinements (DefinedBoxes).\n *\n * The definitions are read like any of the reader's rows (`/api/query`, routed\n * to the tenant by core.js), so the fields a record is shown with are the ones\n * the server will hold its write to. Loaded on demand (onDemand.tsx): an App\n * without a bound column never fetches this.\n */\nimport { useQuery } from '@tanstack/react-query';\nimport { useEffect, useMemo, useState, type ReactNode } from 'react';\nimport { api, findTable, state } from '../core.js';\nimport { ownedBy } from '../requestIdentity.js';\nimport { humanName } from '@mistriwork/engine/shared/model.js';\nimport { DEFINITIONS_MOST, type DefinedBinding, type DefinedField } from '@mistriwork/engine/shared/definedFields.js';\nimport {\n definedFromInput,\n definedObject,\n definitionColumns,\n definitionFilter,\n readDefinitions,\n} from '@mistriwork/engine/shared/definedValues.js';\nimport type { ColumnMeta, TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport type { DefinedFold } from '../recordDrafts.js';\nimport { Editable } from './Editable.js';\nimport { Value } from './Value.js';\nimport type { PlatformControl } from './NewRecord.js';\nimport { fieldInput } from './newRecordModel.js';\nimport type { Box } from './FilterBoxes.js';\n\n/** The fields a record of this `per` value has, in their order; a definitions table this reader cannot read has none. */\nfunction useDefinitions(binding: DefinedBinding, per: unknown, connection?: string) {\n const from = findTable(binding.from) as TableMeta | undefined;\n const owner = connection || (state.activeConnection as string | null) || '';\n const scoped = binding.per ? (per === undefined || per === null || per === '' ? null : String(per)) : null;\n return useQuery({\n queryKey: ['defined-fields', owner, binding.from, binding.per ?? '', scoped],\n enabled: Boolean(from),\n staleTime: 30_000,\n queryFn: async () => {\n const filter = definitionFilter(binding.per, per);\n const data = (await api('/api/query', {\n ...ownedBy(owner),\n table: from!.id,\n columns: definitionColumns(from!, binding.per),\n ...(filter ? { filter } : {}),\n limit: DEFINITIONS_MOST,\n offset: 0,\n })) as { rows?: Record<string, unknown>[] };\n return readDefinitions(data.rows ?? [], binding.per);\n },\n });\n}\n\nconst TYPES: Record<DefinedField['type'], string> = {\n text: 'text',\n textarea: 'text',\n number: 'numeric',\n money: 'numeric',\n date: 'date',\n datetime: 'timestamp',\n bool: 'boolean',\n choice: 'text',\n choices: 'text',\n};\n\n/** A field as a column the platform's controls draw: `specs.capacity`, of the type its definition names. */\nfunction fieldColumn(column: string, field: DefinedField): ColumnMeta & { allowed?: string[] } {\n return {\n name: `${column}.${field.key}`,\n type: TYPES[field.type],\n nullable: true,\n primaryKey: false,\n ...(field.type === 'choice' && field.options.length ? { allowed: field.options } : {}),\n };\n}\n\n/** A value as a box holds it: a list as its choices with commas, a yes or no as the flag controls spell it. */\nfunction boxText(field: DefinedField, value: unknown): string | null {\n if (value === undefined || value === null) return null;\n if (Array.isArray(value)) return value.join(', ');\n if (field.type === 'bool' && typeof value === 'boolean') return value ? '1' : '0';\n return String(value);\n}\n\n/** What a page shows for a value: a list said with commas, a yes or no as a flag column says one. */\nconst shownValue = (field: DefinedField, value: unknown) =>\n Array.isArray(value) ? value.join(', ') : field.type === 'bool' && typeof value === 'boolean' ? (value ? 1 : 0) : value;\n\n/** The keys an object holds, as fields to show where no definition can be read: said, never edited. */\nconst keysOf = (object: Record<string, unknown>): DefinedField[] =>\n Object.keys(object).map((key) => ({ key, label: humanName(key), type: 'text', options: [], required: false }));\n\n/** The record page: one `page-field` per definition, in the section's own list, editable where the record is. */\nexport function DefinedFields({\n base,\n row,\n column,\n binding,\n recordKey,\n editing,\n onSaved,\n isCurrent,\n connection,\n}: {\n base: TableMeta;\n row: Record<string, unknown>;\n column: string;\n binding: DefinedBinding;\n recordKey: Record<string, unknown>;\n editing: boolean;\n onSaved?: (opts?: { inPlace?: boolean }) => void;\n isCurrent?: () => boolean;\n connection?: string;\n}) {\n const definitions = useDefinitions(binding, binding.per ? row[binding.per] : undefined, connection);\n const object = useMemo(() => definedObject(row[column]) ?? {}, [row, column]);\n // One row per draw, so an editor's \"this is what was saved\" stays with the row it was read from.\n const fieldRow = useMemo(() => {\n const shown: Record<string, unknown> = { ...row };\n for (const field of definitions.data ?? []) shown[`${column}.${field.key}`] = boxText(field, object[field.key]);\n return shown;\n }, [row, column, object, definitions.data]);\n if (definitions.isPending && definitions.fetchStatus !== 'idle') return null;\n const read = definitions.data !== undefined;\n const fields = read ? definitions.data : keysOf(object);\n return (\n <>\n {fields.map((field) => {\n const meta = fieldColumn(column, field);\n const value = object[field.key];\n let dd: ReactNode;\n if (editing && read) {\n const defined: DefinedFold = { column, label: field.label, object, toValue: (text) => definedFromInput(field, text) };\n dd = (\n <dd className=\"page-field-edit\">\n <Editable\n table={base}\n row={fieldRow}\n column={{ ...meta, defined } as ColumnMeta}\n recordKey={recordKey}\n onSaved={onSaved}\n isCurrent={isCurrent}\n app\n display={(next) => <Value col={meta} value={next === null ? null : shownValue(field, definedFromInput(field, next))} />}\n />\n </dd>\n );\n } else if (value === undefined || value === null || value === '') {\n dd = (\n <dd className=\"null\" title=\"null\">\n —\n </dd>\n );\n } else {\n dd = (\n <dd>\n <Value col={meta} value={shownValue(field, value)} />\n </dd>\n );\n }\n return (\n <div key={field.key} className=\"page-field\">\n <dt title={field.help ?? meta.name}>{field.label}</dt>\n {dd}\n </div>\n );\n })}\n </>\n );\n}\n\n/**\n * The New form: one field per definition the chosen `per` value picks, drawn\n * with the form's own controls; the object travels as the column's JSON text.\n * A refusal naming `specs.capacity` is said under that field.\n */\nexport function DefinedInputs({\n column,\n binding,\n per,\n value,\n onChange,\n errors,\n connection,\n Control,\n}: {\n column: string;\n binding: DefinedBinding;\n per: unknown;\n /** The New form's own control, handed in (NewRecord.tsx loads this module, so it cannot import it back). */\n Control: typeof PlatformControl;\n value: string;\n onChange: (text: string) => void;\n errors: readonly { field: string; message: string }[];\n connection?: string;\n}) {\n const definitions = useDefinitions(binding, per, connection);\n const object = definedObject(value) ?? {};\n const [boxes, setBoxes] = useState<Record<string, string>>({});\n const set = (field: DefinedField, text: string) => {\n setBoxes((previous) => ({ ...previous, [field.key]: text }));\n const next = { ...object };\n const typed = definedFromInput(field, text);\n if (typed === undefined) delete next[field.key];\n else next[field.key] = typed;\n onChange(JSON.stringify(next));\n };\n return (\n <>\n {(definitions.data ?? []).map((field) => {\n const meta = fieldColumn(column, field);\n const name = meta.name;\n const error = errors.find((candidate) => candidate.field === name)?.message;\n const errorId = `${name}-error`;\n const helpId = field.help ? `${name}-help` : undefined;\n const text = Object.hasOwn(boxes, field.key) ? boxes[field.key] : (boxText(field, object[field.key]) ?? '');\n const kind = fieldInput(meta, {\n required: field.required,\n hasStart: false,\n reference: false,\n multiline: field.type === 'textarea',\n money: field.type === 'money',\n });\n return (\n <div key={field.key} className={`insert-field form-field${error ? ' missing is-invalid' : ''}`}>\n <label className=\"form-field-label\">\n {field.label}\n {field.required && <span className=\"req\">*</span>}\n </label>\n {field.type === 'choices' ? (\n <div className=\"command-choices insert-choices\" role=\"group\" aria-label={field.label}>\n {field.options.map((option) => {\n const chosen = text.split(',').map((item) => item.trim());\n return (\n <label className=\"command-choice\" key={option}>\n <input\n type=\"checkbox\"\n checked={chosen.includes(option)}\n onChange={(event) =>\n set(\n field,\n field.options.filter((item) => (item === option ? event.target.checked : chosen.includes(item))).join(', '),\n )\n }\n />\n {option}\n </label>\n );\n })}\n </div>\n ) : (\n <Control\n column={meta}\n app\n required={field.required}\n assigned={null}\n spoken={field.label}\n target={() => undefined}\n value={text}\n kind={kind}\n onChange={(next) => set(field, next)}\n register={() => {}}\n explicitNull={false}\n errorId={error ? errorId : undefined}\n helpId={helpId}\n />\n )}\n {field.help && (\n <p id={helpId} className=\"form-field-hint\">\n {field.help}\n </p>\n )}\n <span id={errorId} className=\"insert-missing\" aria-live=\"polite\" hidden={!error}>\n {error}\n </span>\n </div>\n );\n })}\n </>\n );\n}\n\n/* The facet a field is asked with: a choice is a checklist of its options, a\n yes or no a toggle, a list of choices its options asked with `has`, a\n number what its values are (a range or a short list); text and a date are\n a box. */\nconst BOX_KINDS: Record<DefinedField['type'], Box['kind']> = {\n text: 'text',\n textarea: 'text',\n number: 'text',\n money: 'text',\n date: 'text',\n datetime: 'text',\n bool: 'flag',\n choice: 'enum',\n choices: 'tags',\n};\n\n/**\n * A list's refinements: a bound column in a view's `filters` stands for one\n * box per field, handed to the list (AppList.tsx), which draws them as it\n * draws any — the rail's facets, the bar's pickers, chips that say their\n * labels. The fields are those of the list's `per` where it asks one value\n * (`category_id = 3`), and every field otherwise.\n */\nexport function DefinedBoxes({\n column,\n binding,\n per,\n onBoxes,\n}: {\n column: string;\n binding: DefinedBinding;\n per: string | undefined;\n onBoxes: (column: string, boxes: Box[]) => void;\n}) {\n const definitions = useDefinitions(per === undefined ? { from: binding.from } : binding, per);\n useEffect(() => {\n if (!definitions.data) return;\n onBoxes(\n column,\n definitions.data.map((field) => {\n const meta = { ...fieldColumn(column, field), ...(field.type === 'choices' ? { allowed: field.options } : {}) };\n return { column: meta.name, label: field.label, kind: BOX_KINDS[field.type], meta };\n }),\n );\n }, [definitions.data]); // eslint-disable-line react-hooks/exhaustive-deps\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as writeAllowed } from "./shared-
|
|
1
|
+
import { U as writeAllowed } from "./shared-BoLbc2WD.js";
|
|
2
2
|
// packages/kit/src/client/actionGrants.ts
|
|
3
3
|
/**
|
|
4
4
|
* What this reader may run on a table, as the server said in the App payload: the fixed actions a role
|
|
@@ -25,4 +25,4 @@ function mayRunAny(app, tableId, actions) {
|
|
|
25
25
|
}
|
|
26
26
|
export { mayRunAny as n, grantedActionIds as t };
|
|
27
27
|
|
|
28
|
-
//# sourceMappingURL=shared-
|
|
28
|
+
//# sourceMappingURL=shared-eZ0SB_zm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-
|
|
1
|
+
{"version":3,"file":"shared-eZ0SB_zm.js","names":[],"sources":["../../../kit/src/client/actionGrants.ts"],"sourcesContent":["/**\n * What this reader may run on a table, as the server said in the App payload: the fixed actions a role\n * of theirs runs on a table it does not write (`roles.<role>.actions`), as action ids by table id, and\n * whether any verb at all is theirs. A runtime answer the server asks again inside every write; here it\n * only decides which buttons are drawn. The kit's: its lists and the record page draw a verb by it, in\n * whichever shell serves the payload, and it reads a verb by its id and command alone.\n */\nimport { writeAllowed } from './core.js';\n\n/** A verb as the grants read it: its id, and the command it runs where it runs one. */\ninterface Verb {\n id: string;\n command?: { id: string };\n}\n\nexport function grantedActionIds(\n app: { grantedActions?: Record<string, string[]> } | null | undefined,\n tableId: string,\n): readonly string[] {\n const granted = app?.grantedActions;\n return granted && Object.hasOwn(granted, tableId) ? granted[tableId] : [];\n}\n\n/**\n * Whether this reader may run any of a table's verbs here (ActionBar judges each again): a granted\n * command, or a fixed action on a table they write or one a role of theirs runs without write. It reads\n * only the App payload and the write scope, both known when a list first draws, so a row's ⋯ is decided\n * before the first row and never appears and then vanishes.\n */\nexport function mayRunAny(\n app: { grantedCommands?: readonly string[]; grantedActions?: Record<string, string[]> } | null | undefined,\n tableId: string,\n actions: readonly Verb[],\n): boolean {\n const commands = app?.grantedCommands ?? [];\n const writes = writeAllowed(tableId);\n const granted = grantedActionIds(app, tableId);\n return actions.some((action) => (action.command ? commands.includes(action.command.id) : writes || granted.includes(action.id)));\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,iBACd,KACA,SACmB;CACnB,MAAM,UAAU,KAAK;CACrB,OAAO,WAAW,OAAO,OAAO,SAAS,OAAO,IAAI,QAAQ,WAAW,CAAC;AAC1E;;;;;;;AAQA,SAAgB,UACd,KACA,SACA,SACS;CACT,MAAM,WAAW,KAAK,mBAAmB,CAAC;CAC1C,MAAM,SAAS,aAAa,OAAO;CACnC,MAAM,UAAU,iBAAiB,KAAK,OAAO;CAC7C,OAAO,QAAQ,MAAM,WAAY,OAAO,UAAU,SAAS,SAAS,OAAO,QAAQ,EAAE,IAAI,UAAU,QAAQ,SAAS,OAAO,EAAE,CAAE;AACjI"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { nt as Button } from "./shared-poc11xxo.js";
|
|
2
2
|
import { gt as defineMessages } from "./shared-DJZjSi3J.js";
|
|
3
|
-
import { i as api } from "./shared-
|
|
3
|
+
import { i as api } from "./shared-BoLbc2WD.js";
|
|
4
4
|
import { t as Field } from "./shared-CERG8O1B.js";
|
|
5
5
|
import { useEffect, useState } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -185,4 +185,4 @@ function IntegrationsForm() {
|
|
|
185
185
|
}
|
|
186
186
|
export { IntegrationsForm };
|
|
187
187
|
|
|
188
|
-
//# sourceMappingURL=shared-
|
|
188
|
+
//# sourceMappingURL=shared-frKFb79C.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-L90bWW8e.js","names":[],"sources":["../../src/client/copy/dashboards/components/IntegrationsForm.ts","../../src/client/components/IntegrationsForm.tsx"],"sourcesContent":["/** What IntegrationsForm says, in the dashboards room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n loading: 'Loading integrations…',\n couldNotLoad: 'Integrations could not be loaded.',\n readOnly: \"Only this organization's admins can change its integrations.\",\n none: 'This App uses no integrations.',\n set: 'Set {date}',\n notSet: 'Not set',\n webhook: 'Webhook address',\n webhookHint: 'Give this to the provider as the address it sends events to.',\n channel: 'Sends {channel} messages.',\n newValue: 'New value',\n keep: 'Leave empty to keep the saved value.',\n remove: 'Remove',\n save: 'Save',\n saving: 'Saving…',\n saved: 'Saved. The next call uses it.',\n couldNotSave: 'The secrets could not be saved.',\n});\n","/**\n * The integrations' settings screen: each integration the App's\n * jobs module lists, its secrets set or not — the server never sends a\n * value back, so nothing here can show one — the webhook address its\n * provider sends events to, and the channel it sends on. An editor (the\n * jobs module's `integrations.editors`) types a new value and saves it;\n * anyone else reads the same form, without the inputs. Loaded on demand\n * (Dashboard.tsx), so none of it stands in a first paint.\n */\nimport { useEffect, useState } from 'react';\nimport { api } from '@mistriwork/kit/client/core.js';\nimport { Button } from '@mistriwork/ui/Button.js';\nimport { Field } from '@mistriwork/ui/Field.js';\nimport './IntegrationsForm.css';\nimport { say } from '../copy/dashboards/components/IntegrationsForm.js';\n\ninterface Secret {\n name: string;\n set: boolean;\n savedAt: number | null;\n}\ninterface Integration {\n name: string;\n secrets: Secret[];\n webhook: string | null;\n channel: string | null;\n}\ninterface Reply {\n integrations: Integration[];\n editor: boolean;\n error?: string;\n}\n\nfunction IntegrationCard({ integration, editor, saved }: { integration: Integration; editor: boolean; saved: (reply: Reply) => void }) {\n const [draft, setDraft] = useState<Record<string, string | null>>({});\n const [busy, setBusy] = useState(false);\n const [message, setMessage] = useState('');\n const changed = Object.keys(draft).filter((name) => draft[name] === null || !!draft[name]?.trim());\n const save = async () => {\n if (busy || !changed.length) return;\n setBusy(true);\n setMessage('');\n try {\n const got = (await api('/api/integrations/save', {\n integration: integration.name,\n secrets: Object.fromEntries(changed.map((name) => [name, draft[name]])),\n })) as Reply;\n if (got.error) setMessage(got.error);\n else {\n setDraft({});\n setMessage(say('saved'));\n saved(got);\n }\n } catch (error) {\n setMessage(error instanceof Error ? error.message : say('couldNotSave'));\n } finally {\n setBusy(false);\n }\n };\n return (\n <form\n className=\"integrations-form-card\"\n aria-label={integration.name}\n onSubmit={(event) => {\n event.preventDefault();\n void save();\n }}\n >\n <h3>{integration.name}</h3>\n {integration.channel ? <p className=\"integrations-form-note\">{say('channel', { channel: integration.channel })}</p> : null}\n {integration.webhook ? (\n <Field label={say('webhook')} hint={say('webhookHint')} size=\"compact\">\n <input\n className=\"field-control integrations-form-address\"\n readOnly\n value={integration.webhook}\n onFocus={(event) => event.target.select()}\n />\n </Field>\n ) : null}\n {integration.secrets.map((secret) => {\n const status = secret.set && secret.savedAt ? say('set', { date: new Date(secret.savedAt).toLocaleDateString() }) : say('notSet');\n return editor ? (\n <Field key={secret.name} label={secret.name} hint={secret.set ? `${status}. ${say('keep')}` : status} size=\"compact\">\n <input\n className=\"field-control\"\n type=\"password\"\n name={secret.name}\n autoComplete=\"off\"\n spellCheck={false}\n maxLength={4096}\n disabled={busy || draft[secret.name] === null}\n placeholder={draft[secret.name] === null ? say('remove') : say('newValue')}\n value={draft[secret.name] ?? ''}\n onChange={(event) => setDraft((current) => ({ ...current, [secret.name]: event.target.value }))}\n />\n </Field>\n ) : (\n <p key={secret.name} className=\"integrations-form-secret\">\n <span>{secret.name}</span>\n <span>{status}</span>\n </p>\n );\n })}\n {editor ? (\n <footer className=\"form-actions\">\n <p className=\"integrations-form-status\" role=\"status\">\n {message}\n </p>\n {integration.secrets.some((secret) => secret.set) ? (\n <Button\n size=\"compact\"\n disabled={busy}\n onClick={() =>\n setDraft(Object.fromEntries(integration.secrets.filter((secret) => secret.set).map((secret) => [secret.name, null])))\n }\n >\n {say('remove')}\n </Button>\n ) : null}\n <Button intent=\"primary\" size=\"compact\" type=\"submit\" busy={busy} busyLabel={say('saving')} disabled={!changed.length}>\n {say('save')}\n </Button>\n </footer>\n ) : null}\n </form>\n );\n}\n\nexport function IntegrationsForm() {\n const [reply, setReply] = useState<Reply | undefined>();\n const [failed, setFailed] = useState('');\n useEffect(() => {\n let alive = true;\n void (async () => {\n try {\n const got = (await api('/api/integrations', {})) as Reply;\n if (!alive) return;\n if (got.error) setFailed(got.error);\n else setReply(got);\n } catch (error) {\n if (alive) setFailed(error instanceof Error ? error.message : say('couldNotLoad'));\n }\n })();\n return () => {\n alive = false;\n };\n }, []);\n if (failed)\n return (\n <p className=\"integrations-form-note\" role=\"alert\">\n {failed}\n </p>\n );\n if (!reply)\n return (\n <p className=\"integrations-form-note\" role=\"status\">\n {say('loading')}\n </p>\n );\n if (!reply.integrations.length) return <p className=\"integrations-form-note\">{say('none')}</p>;\n return (\n <div className=\"integrations-form\">\n {!reply.editor && <p className=\"integrations-form-note\">{say('readOnly')}</p>}\n {reply.integrations.map((integration) => (\n <IntegrationCard key={integration.name} integration={integration} editor={reply.editor} saved={setReply} />\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-frKFb79C.js","names":[],"sources":["../../src/client/copy/dashboards/components/IntegrationsForm.ts","../../src/client/components/IntegrationsForm.tsx"],"sourcesContent":["/** What IntegrationsForm says, in the dashboards room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n loading: 'Loading integrations…',\n couldNotLoad: 'Integrations could not be loaded.',\n readOnly: \"Only this organization's admins can change its integrations.\",\n none: 'This App uses no integrations.',\n set: 'Set {date}',\n notSet: 'Not set',\n webhook: 'Webhook address',\n webhookHint: 'Give this to the provider as the address it sends events to.',\n channel: 'Sends {channel} messages.',\n newValue: 'New value',\n keep: 'Leave empty to keep the saved value.',\n remove: 'Remove',\n save: 'Save',\n saving: 'Saving…',\n saved: 'Saved. The next call uses it.',\n couldNotSave: 'The secrets could not be saved.',\n});\n","/**\n * The integrations' settings screen: each integration the App's\n * jobs module lists, its secrets set or not — the server never sends a\n * value back, so nothing here can show one — the webhook address its\n * provider sends events to, and the channel it sends on. An editor (the\n * jobs module's `integrations.editors`) types a new value and saves it;\n * anyone else reads the same form, without the inputs. Loaded on demand\n * (Dashboard.tsx), so none of it stands in a first paint.\n */\nimport { useEffect, useState } from 'react';\nimport { api } from '@mistriwork/kit/client/core.js';\nimport { Button } from '@mistriwork/ui/Button.js';\nimport { Field } from '@mistriwork/ui/Field.js';\nimport './IntegrationsForm.css';\nimport { say } from '../copy/dashboards/components/IntegrationsForm.js';\n\ninterface Secret {\n name: string;\n set: boolean;\n savedAt: number | null;\n}\ninterface Integration {\n name: string;\n secrets: Secret[];\n webhook: string | null;\n channel: string | null;\n}\ninterface Reply {\n integrations: Integration[];\n editor: boolean;\n error?: string;\n}\n\nfunction IntegrationCard({ integration, editor, saved }: { integration: Integration; editor: boolean; saved: (reply: Reply) => void }) {\n const [draft, setDraft] = useState<Record<string, string | null>>({});\n const [busy, setBusy] = useState(false);\n const [message, setMessage] = useState('');\n const changed = Object.keys(draft).filter((name) => draft[name] === null || !!draft[name]?.trim());\n const save = async () => {\n if (busy || !changed.length) return;\n setBusy(true);\n setMessage('');\n try {\n const got = (await api('/api/integrations/save', {\n integration: integration.name,\n secrets: Object.fromEntries(changed.map((name) => [name, draft[name]])),\n })) as Reply;\n if (got.error) setMessage(got.error);\n else {\n setDraft({});\n setMessage(say('saved'));\n saved(got);\n }\n } catch (error) {\n setMessage(error instanceof Error ? error.message : say('couldNotSave'));\n } finally {\n setBusy(false);\n }\n };\n return (\n <form\n className=\"integrations-form-card\"\n aria-label={integration.name}\n onSubmit={(event) => {\n event.preventDefault();\n void save();\n }}\n >\n <h3>{integration.name}</h3>\n {integration.channel ? <p className=\"integrations-form-note\">{say('channel', { channel: integration.channel })}</p> : null}\n {integration.webhook ? (\n <Field label={say('webhook')} hint={say('webhookHint')} size=\"compact\">\n <input\n className=\"field-control integrations-form-address\"\n readOnly\n value={integration.webhook}\n onFocus={(event) => event.target.select()}\n />\n </Field>\n ) : null}\n {integration.secrets.map((secret) => {\n const status = secret.set && secret.savedAt ? say('set', { date: new Date(secret.savedAt).toLocaleDateString() }) : say('notSet');\n return editor ? (\n <Field key={secret.name} label={secret.name} hint={secret.set ? `${status}. ${say('keep')}` : status} size=\"compact\">\n <input\n className=\"field-control\"\n type=\"password\"\n name={secret.name}\n autoComplete=\"off\"\n spellCheck={false}\n maxLength={4096}\n disabled={busy || draft[secret.name] === null}\n placeholder={draft[secret.name] === null ? say('remove') : say('newValue')}\n value={draft[secret.name] ?? ''}\n onChange={(event) => setDraft((current) => ({ ...current, [secret.name]: event.target.value }))}\n />\n </Field>\n ) : (\n <p key={secret.name} className=\"integrations-form-secret\">\n <span>{secret.name}</span>\n <span>{status}</span>\n </p>\n );\n })}\n {editor ? (\n <footer className=\"form-actions\">\n <p className=\"integrations-form-status\" role=\"status\">\n {message}\n </p>\n {integration.secrets.some((secret) => secret.set) ? (\n <Button\n size=\"compact\"\n disabled={busy}\n onClick={() =>\n setDraft(Object.fromEntries(integration.secrets.filter((secret) => secret.set).map((secret) => [secret.name, null])))\n }\n >\n {say('remove')}\n </Button>\n ) : null}\n <Button intent=\"primary\" size=\"compact\" type=\"submit\" busy={busy} busyLabel={say('saving')} disabled={!changed.length}>\n {say('save')}\n </Button>\n </footer>\n ) : null}\n </form>\n );\n}\n\nexport function IntegrationsForm() {\n const [reply, setReply] = useState<Reply | undefined>();\n const [failed, setFailed] = useState('');\n useEffect(() => {\n let alive = true;\n void (async () => {\n try {\n const got = (await api('/api/integrations', {})) as Reply;\n if (!alive) return;\n if (got.error) setFailed(got.error);\n else setReply(got);\n } catch (error) {\n if (alive) setFailed(error instanceof Error ? error.message : say('couldNotLoad'));\n }\n })();\n return () => {\n alive = false;\n };\n }, []);\n if (failed)\n return (\n <p className=\"integrations-form-note\" role=\"alert\">\n {failed}\n </p>\n );\n if (!reply)\n return (\n <p className=\"integrations-form-note\" role=\"status\">\n {say('loading')}\n </p>\n );\n if (!reply.integrations.length) return <p className=\"integrations-form-note\">{say('none')}</p>;\n return (\n <div className=\"integrations-form\">\n {!reply.editor && <p className=\"integrations-form-note\">{say('readOnly')}</p>}\n {reply.integrations.map((integration) => (\n <IntegrationCard key={integration.name} integration={integration} editor={reply.editor} saved={setReply} />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAGA,IAAa,MAAM,eAAe;CAChC,SAAS;CACT,cAAc;CACd,UAAU;CACV,MAAM;CACN,KAAK;CACL,QAAQ;CACR,SAAS;CACT,aAAa;CACb,SAAS;CACT,UAAU;CACV,MAAM;CACN,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,OAAO;CACP,cAAc;AAChB,CAAC;;;;;;;;;;;ACaD,SAAS,gBAAgB,EAAE,aAAa,QAAQ,SAAuF;CACrI,MAAM,CAAC,OAAO,YAAY,SAAwC,CAAC,CAAC;CACpE,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,CAAC,SAAS,cAAc,SAAS,EAAE;CACzC,MAAM,UAAU,OAAO,KAAK,KAAK,CAAC,CAAC,QAAQ,SAAS,MAAM,UAAU,QAAQ,CAAC,CAAC,MAAM,KAAK,EAAE,KAAK,CAAC;CACjG,MAAM,OAAO,YAAY;EACvB,IAAI,QAAQ,CAAC,QAAQ,QAAQ;EAC7B,QAAQ,IAAI;EACZ,WAAW,EAAE;EACb,IAAI;GACF,MAAM,MAAO,MAAM,IAAI,0BAA0B;IAC/C,aAAa,YAAY;IACzB,SAAS,OAAO,YAAY,QAAQ,KAAK,SAAS,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;GACxE,CAAC;GACD,IAAI,IAAI,OAAO,WAAW,IAAI,KAAK;QAC9B;IACH,SAAS,CAAC,CAAC;IACX,WAAW,IAAI,OAAO,CAAC;IACvB,MAAM,GAAG;GACX;EACF,SAAS,OAAO;GACd,WAAW,iBAAiB,QAAQ,MAAM,UAAU,IAAI,cAAc,CAAC;EACzE,UAAU;GACR,QAAQ,KAAK;EACf;CACF;CACA,OACE,qBAAC,QAAD;EACE,WAAU;EACV,cAAY,YAAY;EACxB,WAAW,UAAU;GACnB,MAAM,eAAe;GACrB,KAAU;EACZ;EANF,UAAA;GAQE,oBAAC,MAAD,EAAA,UAAK,YAAY,KAAS,CAAA;GACzB,YAAY,UAAU,oBAAC,KAAD;IAAG,WAAU;IAA0B,UAAA,IAAI,WAAW,EAAE,SAAS,YAAY,QAAQ,CAAC;GAAK,CAAA,IAAI;GACrH,YAAY,UACX,oBAAC,OAAD;IAAO,OAAO,IAAI,SAAS;IAAG,MAAM,IAAI,aAAa;IAAG,MAAK;IAC3D,UAAA,oBAAC,SAAD;KACE,WAAU;KACV,UAAA;KACA,OAAO,YAAY;KACnB,UAAU,UAAU,MAAM,OAAO,OAAO;IACzC,CAAA;GACI,CAAA,IACL;GACH,YAAY,QAAQ,KAAK,WAAW;IACnC,MAAM,SAAS,OAAO,OAAO,OAAO,UAAU,IAAI,OAAO,EAAE,MAAM,IAAI,KAAK,OAAO,OAAO,CAAC,CAAC,mBAAmB,EAAE,CAAC,IAAI,IAAI,QAAQ;IAChI,OAAO,SACL,oBAAC,OAAD;KAAyB,OAAO,OAAO;KAAM,MAAM,OAAO,MAAM,GAAG,OAAO,IAAI,IAAI,MAAM,MAAM;KAAQ,MAAK;KACzG,UAAA,oBAAC,SAAD;MACE,WAAU;MACV,MAAK;MACL,MAAM,OAAO;MACb,cAAa;MACb,YAAY;MACZ,WAAW;MACX,UAAU,QAAQ,MAAM,OAAO,UAAU;MACzC,aAAa,MAAM,OAAO,UAAU,OAAO,IAAI,QAAQ,IAAI,IAAI,UAAU;MACzE,OAAO,MAAM,OAAO,SAAS;MAC7B,WAAW,UAAU,UAAU,aAAa;OAAE,GAAG;QAAU,OAAO,OAAO,MAAM,OAAO;MAAM,EAAE;KAC/F,CAAA;IACI,GAbK,OAAO,IAaZ,IAEP,qBAAC,KAAD;KAAqB,WAAU;KAA/B,UAAA,CACE,oBAAC,QAAD,EAAA,UAAO,OAAO,KAAW,CAAA,GACzB,oBAAC,QAAD,EAAA,UAAO,OAAa,CAAA,CACnB;IAHK,GAAA,OAAO,IAGZ;GAEP,CAAC;GACA,SACC,qBAAC,UAAD;IAAQ,WAAU;IAAlB,UAAA;KACE,oBAAC,KAAD;MAAG,WAAU;MAA2B,MAAK;MAC1C,UAAA;KACA,CAAA;KACF,YAAY,QAAQ,MAAM,WAAW,OAAO,GAAG,IAC9C,oBAAC,QAAD;MACE,MAAK;MACL,UAAU;MACV,eACE,SAAS,OAAO,YAAY,YAAY,QAAQ,QAAQ,WAAW,OAAO,GAAG,CAAC,CAAC,KAAK,WAAW,CAAC,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC;MAGrH,UAAA,IAAI,QAAQ;KACP,CAAA,IACN;KACJ,oBAAC,QAAD;MAAQ,QAAO;MAAU,MAAK;MAAU,MAAK;MAAe;MAAM,WAAW,IAAI,QAAQ;MAAG,UAAU,CAAC,QAAQ;MAC5G,UAAA,IAAI,MAAM;KACL,CAAA;IACF;GACN,CAAA,IAAA;EACA;;AAEV;AAEA,SAAgB,mBAAmB;CACjC,MAAM,CAAC,OAAO,YAAY,SAA4B;CACtD,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CACvC,gBAAgB;EACd,IAAI,QAAQ;EACZ,CAAM,YAAY;GAChB,IAAI;IACF,MAAM,MAAO,MAAM,IAAI,qBAAqB,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO;IACZ,IAAI,IAAI,OAAO,UAAU,IAAI,KAAK;SAC7B,SAAS,GAAG;GACnB,SAAS,OAAO;IACd,IAAI,OAAO,UAAU,iBAAiB,QAAQ,MAAM,UAAU,IAAI,cAAc,CAAC;GACnF;EACF,EAAA,CAAG;EACH,aAAa;GACX,QAAQ;EACV;CACF,GAAG,CAAC,CAAC;CACL,IAAI,QACF,OACE,oBAAC,KAAD;EAAG,WAAU;EAAyB,MAAK;EACxC,UAAA;CACA,CAAA;CAEP,IAAI,CAAC,OACH,OACE,oBAAC,KAAD;EAAG,WAAU;EAAyB,MAAK;EACxC,UAAA,IAAI,SAAS;CACb,CAAA;CAEP,IAAI,CAAC,MAAM,aAAa,QAAQ,OAAO,oBAAC,KAAD;EAAG,WAAU;EAA0B,UAAA,IAAI,MAAM;CAAK,CAAA;CAC7F,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,CAAC,MAAM,UAAU,oBAAC,KAAD;GAAG,WAAU;GAA0B,UAAA,IAAI,UAAU;EAAK,CAAA,GAC3E,MAAM,aAAa,KAAK,gBACvB,oBAAC,iBAAD;GAAqD;GAAa,QAAQ,MAAM;GAAQ,OAAO;EAAW,GAApF,YAAY,IAAwE,CAC3G,CACE;;AAET"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as __exportAll } from "./shared-C-UrYobY.js";
|
|
2
2
|
import { nt as Button } from "./shared-poc11xxo.js";
|
|
3
3
|
import { gt as defineMessages } from "./shared-DJZjSi3J.js";
|
|
4
|
-
import { t as onDemand } from "./shared-
|
|
5
|
-
import { C as Loaded, D as Stack, O as Stat, T as Row, b as Empty, f as useRecord, i as useCommand, j as Value, o as useFile, p as useRows, r as useBreakdown, t as useAddressState, v as Card, x as Heading, y as Columns } from "./shared-
|
|
4
|
+
import { t as onDemand } from "./shared-B-BUF9fx.js";
|
|
5
|
+
import { C as Loaded, D as Stack, O as Stat, T as Row, b as Empty, f as useRecord, i as useCommand, j as Value, o as useFile, p as useRows, r as useBreakdown, t as useAddressState, v as Card, x as Heading, y as Columns } from "./shared-TrGbd1FY.js";
|
|
6
6
|
import { t as pageBlocks } from "./shared-CI0xbf3H.js";
|
|
7
7
|
import { createElement } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -142,4 +142,4 @@ function CommandForm({ command, record, label, intent = "secondary", onDone }) {
|
|
|
142
142
|
}
|
|
143
143
|
export { Gantt as a, Panel as c, Tabs as d, Timeline as f, page_exports as h, CommandForm as i, RecordCard as l, definePage as m, Breakdown as n, Grid as o, Tree as p, Chart as r, Metric as s, Assistant as t, Rows as u };
|
|
144
144
|
|
|
145
|
-
//# sourceMappingURL=shared-
|
|
145
|
+
//# sourceMappingURL=shared-hAayNSRA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-
|
|
1
|
+
{"version":3,"file":"shared-hAayNSRA.js","names":[],"sources":["../../src/client/copy/components/components/sdk/page.ts","../../src/client/components/sdk/page.tsx"],"sourcesContent":["/** What sdk/page says, in the custom components room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n definePageTakes: 'definePage takes the page: its label, reads and component.',\n definePageHasNo:\n 'definePage has no \"{name}\". It takes path, label, icon, nav, roles, reads, commands, params, loader, public, description, favorite and component.',\n blocksUnregistered: '@mistriwork/mistri/page: no page has said how its blocks load.',\n});\n","/**\n * `@mistriwork/mistri/page`: a free-form page, one file each (`pages/<path>.page.tsx`); the file's name is its path.\n *\n * const page = definePage({ label: 'Pick walk', reads: ['pick_list'], commands: ['pickList'],\n * params: ['list'], loader: 'pickWalk', component: PickWalk });\n * export default page;\n * function PickWalk({ data }) { const [list, setList] = page.useParam('list'); … }\n *\n * What the page says of itself is read by the server without drawing it\n * (server/app/appPages.ts) and served back as its manifest, which the page\n * is drawn inside (UiPageFrame): the hooks bound to the definition read and\n * run only what it declares, and its loader's result arrives as `data`.\n *\n * `definePage` hands back a component — the page itself — with its hooks on\n * it. They are the SDK's own hooks: `page.useX` is the shape so the types\n * can bind them to this page's reads, commands and parameters\n * (packages/mistri/schema/page.d.ts), and so a linter still sees them as hooks.\n *\n * The blocks are the kit's (kit.tsx), the platform's own command form, the layout's `Grid` and `Panel`, and the\n * platform's sections as components (blocks.tsx), each loaded when a page first draws one.\n * In the page this module is the page's own, reached through the import map\n * like `@mistriwork/mistri/ui`; its value exports are `PAGE_EXPORTS` (shared/uiSdk.ts).\n */\nimport { createElement, type ComponentType, type ReactNode } from 'react';\nimport { useAddressState, useBreakdown, useCommand, useFile, useRecord, useRows } from './hooks.js';\nimport { Button } from './kit.js';\nimport { onDemand } from '@mistriwork/kit/client/components/onDemand.js';\nimport { pageBlocks } from './pageBlocks.js';\nimport { say } from '../../copy/components/components/sdk/page.js';\n\nexport { Card, Columns, Empty, Heading, Loaded, Row, Stack, Stat, Value } from './kit.js';\nexport { Button };\n/* A page's place in its address: `page.useParam` is this hook, typed to the page's `params`; this one is for a module\n the page draws that is not the page itself (a widget, the Console's rooms). */\nexport { useAddressState };\n\n/* The platform's blocks (blocks.tsx): a part of their own, loaded when a page first draws one. They draw the\n platform's rooms, which reach this module again through the host, so the module that draws a free-form page hands\n in how they load (pageBlocks.ts) rather than this one importing them. */\nconst blocks = () => pageBlocks<typeof import('./blocks.js')>(say('blocksUnregistered'));\nexport const Rows = onDemand(blocks, 'Rows');\nexport const RecordCard = onDemand(blocks, 'RecordCard');\nexport const Metric = onDemand(blocks, 'Metric');\nexport const Chart = onDemand(blocks, 'Chart');\nexport const Breakdown = onDemand(blocks, 'Breakdown');\nexport const Timeline = onDemand(blocks, 'Timeline');\nexport const Tree = onDemand(blocks, 'Tree');\nexport const Gantt = onDemand(blocks, 'Gantt');\nexport const Assistant = onDemand(blocks, 'Assistant');\nexport const Tabs = onDemand(blocks, 'Tabs');\n\n/** The page's grid: blocks and panels side by side by their `width`, wrapping as a dashboard's sections do. */\nexport function Grid({ children }: { children?: ReactNode }) {\n return <div className=\"page-body\">{children}</div>;\n}\n\n/** A titled region of the grid, a dashboard section's box: `<Panel title=\"Open lines\" width=\"half\">…</Panel>`. */\nexport function Panel({\n title,\n width = 'full',\n children,\n}: {\n title?: ReactNode;\n width?: 'full' | 'half' | 'third' | 'two-thirds';\n children?: ReactNode;\n}) {\n return (\n <section className={`page-section width-${width}`}>\n {title !== undefined && <h2 className=\"page-section-title\">{title}</h2>}\n {children}\n </section>\n );\n}\n\n/** What a page's component is drawn with: its loader's result, and the props the platform placed it with. */\nexport interface PageProps<D = unknown> {\n data: D;\n props: Readonly<Record<string, unknown>>;\n}\n\nconst FIELDS = ['label', 'icon', 'nav', 'roles', 'reads', 'commands', 'params', 'loader', 'public', 'description', 'favorite'];\n\n/** A page as `definePage` makes it: the component that draws it, its definition and its hooks. */\nexport interface PageDefinition<D = unknown> {\n (props: PageProps<D>): ReactNode;\n readonly definition: Readonly<Record<string, unknown>>;\n readonly useRows: typeof useRows;\n readonly useRecord: typeof useRecord;\n readonly useBreakdown: typeof useBreakdown;\n readonly useFile: typeof useFile;\n readonly useCommand: typeof useCommand;\n readonly useParam: typeof useAddressState;\n}\n\n/** A free-form page: its label, reads, commands, parameters and loader, and the component that draws it. */\nexport function definePage<D = unknown>(\n definition: Record<string, unknown> & { component: ComponentType<PageProps<D>> },\n): PageDefinition<D> {\n if (!definition || typeof definition !== 'object' || typeof definition.component !== 'function')\n throw new TypeError(say('definePageTakes'));\n const { component, ...fields } = definition;\n for (const name of Object.keys(fields)) if (!FIELDS.includes(name)) throw new TypeError(say('definePageHasNo', { name }));\n const draw = component;\n const Page = (props: PageProps<D>) => createElement(draw, props);\n return Object.assign(Page, {\n definition: Object.freeze(fields),\n useRows,\n useRecord,\n useBreakdown,\n useFile,\n useCommand,\n useParam: useAddressState,\n });\n}\n\n/**\n * A command's own form, behind a button: `<CommandForm command=\"releaseOrder\" />`, or on one record,\n * `<CommandForm command=\"pickList\" record={{ id: 12 }} />`. The platform's dialog, the one pipeline;\n * the button is not drawn for a reader who may not run the command.\n */\nexport function CommandForm({\n command,\n record,\n label,\n intent = 'secondary',\n onDone,\n}: {\n command: string;\n record?: Readonly<Record<string, unknown>>;\n label?: ReactNode;\n intent?: 'primary' | 'secondary' | 'quiet';\n onDone?: (outcome: Awaited<ReturnType<ReturnType<typeof useCommand>['open']>>) => void;\n}) {\n const handle = useCommand(command);\n const key = record ?? {};\n if (!handle.granted) return null;\n const busy = handle.pending(key);\n return (\n <Button\n intent={intent}\n busy={busy}\n disabled={busy || handle.available(key) === false}\n onClick={() => void handle.open(key).then((outcome) => onDone?.(outcome))}\n >\n {label ?? handle.label}\n </Button>\n );\n}\n"],"mappings":";;;;;;;;;;AAGA,IAAa,MAAM,eAAe;CAChC,iBAAiB;CACjB,iBACE;CACF,oBAAoB;AACtB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC+BD,IAAM,eAAe,WAAyC,IAAI,oBAAoB,CAAC;AACvF,IAAa,OAAO,SAAS,QAAQ,MAAM;AAC3C,IAAa,aAAa,SAAS,QAAQ,YAAY;AACvD,IAAa,SAAS,SAAS,QAAQ,QAAQ;AAC/C,IAAa,QAAQ,SAAS,QAAQ,OAAO;AAC7C,IAAa,YAAY,SAAS,QAAQ,WAAW;AACrD,IAAa,WAAW,SAAS,QAAQ,UAAU;AACnD,IAAa,OAAO,SAAS,QAAQ,MAAM;AAC3C,IAAa,QAAQ,SAAS,QAAQ,OAAO;AAC7C,IAAa,YAAY,SAAS,QAAQ,WAAW;AACrD,IAAa,OAAO,SAAS,QAAQ,MAAM;;AAG3C,SAAgB,KAAK,EAAE,YAAsC;CAC3D,OAAO,oBAAC,OAAD;EAAK,WAAU;EAAa;CAAc,CAAA;AACnD;;AAGA,SAAgB,MAAM,EACpB,OACA,QAAQ,QACR,YAKC;CACD,OACE,qBAAC,WAAD;EAAS,WAAW,sBAAsB;EAA1C,UAAA,CACG,UAAU,KAAA,KAAa,oBAAC,MAAD;GAAI,WAAU;GAAsB,UAAA;EAAU,CAAA,GACrE,QACM;;AAEb;AAQA,IAAM,SAAS;CAAC;CAAS;CAAQ;CAAO;CAAS;CAAS;CAAY;CAAU;CAAU;CAAU;CAAe;AAAU;;AAe7H,SAAgB,WACd,YACmB;CACnB,IAAI,CAAC,cAAc,OAAO,eAAe,YAAY,OAAO,WAAW,cAAc,YACnF,MAAM,IAAI,UAAU,IAAI,iBAAiB,CAAC;CAC5C,MAAM,EAAE,WAAW,GAAG,WAAW;CACjC,KAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,SAAS,IAAI,GAAG,MAAM,IAAI,UAAU,IAAI,mBAAmB,EAAE,KAAK,CAAC,CAAC;CACxH,MAAM,OAAO;CACb,MAAM,QAAQ,UAAwB,cAAc,MAAM,KAAK;CAC/D,OAAO,OAAO,OAAO,MAAM;EACzB,YAAY,OAAO,OAAO,MAAM;EAChC;EACA;EACA;EACA;EACA;EACA,UAAU;CACZ,CAAC;AACH;;;;;;AAOA,SAAgB,YAAY,EAC1B,SACA,QACA,OACA,SAAS,aACT,UAOC;CACD,MAAM,SAAS,WAAW,OAAO;CACjC,MAAM,MAAM,UAAU,CAAC;CACvB,IAAI,CAAC,OAAO,SAAS,OAAO;CAC5B,MAAM,OAAO,OAAO,QAAQ,GAAG;CAC/B,OACE,oBAAC,QAAD;EACU;EACF;EACN,UAAU,QAAQ,OAAO,UAAU,GAAG,MAAM;EAC5C,eAAe,KAAK,OAAO,KAAK,GAAG,CAAC,CAAC,MAAM,YAAY,SAAS,OAAO,CAAC;EAEvE,UAAA,SAAS,OAAO;CACX,CAAA;AAEZ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Z as Empty, it as useQuery } from "./shared-poc11xxo.js";
|
|
2
2
|
import { Pn as useQueryClient, Wt as formatDateTime, gt as defineMessages } from "./shared-DJZjSi3J.js";
|
|
3
3
|
import { t as useMutation } from "./shared-BSPDIjPQ.js";
|
|
4
|
-
import { L as DropItem, R as DropMenu } from "./shared-
|
|
4
|
+
import { L as DropItem, R as DropMenu } from "./shared-BHsjawAG.js";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
// packages/kit/src/client/copy/record/components/PageFlows.ts
|
|
@@ -203,4 +203,4 @@ function FlowRunItem({ run, open }) {
|
|
|
203
203
|
}
|
|
204
204
|
export { RecordFlows };
|
|
205
205
|
|
|
206
|
-
//# sourceMappingURL=shared-
|
|
206
|
+
//# sourceMappingURL=shared-j_J16p2B.js.map
|