@modern-admin/web 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/standalone/assets/action-component-host-CXIbN-8V.js +2 -0
- package/dist/standalone/assets/action-component-host-CXIbN-8V.js.br +0 -0
- package/dist/standalone/assets/action-component-host-CXIbN-8V.js.gz +0 -0
- package/dist/standalone/assets/action-component-host-CXIbN-8V.js.map +1 -0
- package/dist/standalone/assets/action-page-OsWfKQ6C.js +2 -0
- package/dist/standalone/assets/action-page-OsWfKQ6C.js.br +0 -0
- package/dist/standalone/assets/action-page-OsWfKQ6C.js.gz +0 -0
- package/dist/standalone/assets/action-page-OsWfKQ6C.js.map +1 -0
- package/dist/standalone/assets/{ai-assistant-widget-Dk-VvXD0.js → ai-assistant-widget-Bt4Z7Fmr.js} +2 -2
- package/dist/standalone/assets/ai-assistant-widget-Bt4Z7Fmr.js.br +0 -0
- package/dist/standalone/assets/ai-assistant-widget-Bt4Z7Fmr.js.gz +0 -0
- package/dist/standalone/assets/{ai-assistant-widget-Dk-VvXD0.js.map → ai-assistant-widget-Bt4Z7Fmr.js.map} +1 -1
- package/dist/standalone/assets/arrow-left-CI9hUPwJ.js +2 -0
- package/dist/standalone/assets/arrow-left-CI9hUPwJ.js.map +1 -0
- package/dist/standalone/assets/audit-log-page-2wuGiWg-.js +2 -0
- package/dist/standalone/assets/audit-log-page-2wuGiWg-.js.br +0 -0
- package/dist/standalone/assets/audit-log-page-2wuGiWg-.js.gz +0 -0
- package/dist/standalone/assets/{audit-log-page-BEC79lKy.js.map → audit-log-page-2wuGiWg-.js.map} +1 -1
- package/dist/standalone/assets/{calendar-Pq7dP9RH.js → calendar-BZVUWakC.js} +2 -2
- package/dist/standalone/assets/calendar-BZVUWakC.js.br +0 -0
- package/dist/standalone/assets/calendar-BZVUWakC.js.gz +0 -0
- package/dist/standalone/assets/{calendar-Pq7dP9RH.js.map → calendar-BZVUWakC.js.map} +1 -1
- package/dist/standalone/assets/chart-widget-BtJb6YXV.js +2 -0
- package/dist/standalone/assets/chart-widget-BtJb6YXV.js.br +0 -0
- package/dist/standalone/assets/chart-widget-BtJb6YXV.js.gz +0 -0
- package/dist/standalone/assets/{chart-widget-B7pIeDCP.js.map → chart-widget-BtJb6YXV.js.map} +1 -1
- package/dist/standalone/assets/circle-alert-0EyKeic4.js +2 -0
- package/dist/standalone/assets/circle-alert-0EyKeic4.js.map +1 -0
- package/dist/standalone/assets/{command-B6-wRF2R.js → command-BNF_evMy.js} +2 -2
- package/dist/standalone/assets/command-BNF_evMy.js.br +0 -0
- package/dist/standalone/assets/command-BNF_evMy.js.gz +0 -0
- package/dist/standalone/assets/{command-B6-wRF2R.js.map → command-BNF_evMy.js.map} +1 -1
- package/dist/standalone/assets/{date-picker-BAp85mMa.js → date-picker-LfbUehd1.js} +2 -2
- package/dist/standalone/assets/date-picker-LfbUehd1.js.br +0 -0
- package/dist/standalone/assets/date-picker-LfbUehd1.js.gz +0 -0
- package/dist/standalone/assets/{date-picker-BAp85mMa.js.map → date-picker-LfbUehd1.js.map} +1 -1
- package/dist/standalone/assets/{dist-CvKz-wgE.js → dist-BSbFjTlr.js} +2 -2
- package/dist/standalone/assets/dist-BSbFjTlr.js.br +0 -0
- package/dist/standalone/assets/dist-BSbFjTlr.js.gz +0 -0
- package/dist/standalone/assets/dist-BSbFjTlr.js.map +1 -0
- package/dist/standalone/assets/{dist-Dkym1-ts.js → dist-BcL2U6dT.js} +2 -2
- package/dist/standalone/assets/dist-BcL2U6dT.js.br +0 -0
- package/dist/standalone/assets/dist-BcL2U6dT.js.gz +0 -0
- package/dist/standalone/assets/{dist-Dkym1-ts.js.map → dist-BcL2U6dT.js.map} +1 -1
- package/dist/standalone/assets/edit-page-DCRB9Y_q.js +2 -0
- package/dist/standalone/assets/edit-page-DCRB9Y_q.js.br +0 -0
- package/dist/standalone/assets/edit-page-DCRB9Y_q.js.gz +0 -0
- package/dist/standalone/assets/{edit-page-BVwML9yD.js.map → edit-page-DCRB9Y_q.js.map} +1 -1
- package/dist/standalone/assets/ellipsis-lEjcTxo0.js +2 -0
- package/dist/standalone/assets/ellipsis-lEjcTxo0.js.map +1 -0
- package/dist/standalone/assets/{empty-BmE-qyE9.js → empty-DAEAjFd3.js} +2 -2
- package/dist/standalone/assets/empty-DAEAjFd3.js.br +0 -0
- package/dist/standalone/assets/empty-DAEAjFd3.js.gz +0 -0
- package/dist/standalone/assets/{empty-BmE-qyE9.js.map → empty-DAEAjFd3.js.map} +1 -1
- package/dist/standalone/assets/global-search-dialog-HMLztOho.js +2 -0
- package/dist/standalone/assets/global-search-dialog-HMLztOho.js.br +0 -0
- package/dist/standalone/assets/global-search-dialog-HMLztOho.js.gz +0 -0
- package/dist/standalone/assets/{global-search-dialog-C3Ri2VRv.js.map → global-search-dialog-HMLztOho.js.map} +1 -1
- package/dist/standalone/assets/{heavy-fields-aI_gOI6-.js → heavy-fields-ZuqfOFMv.js} +2 -2
- package/dist/standalone/assets/heavy-fields-ZuqfOFMv.js.br +0 -0
- package/dist/standalone/assets/heavy-fields-ZuqfOFMv.js.gz +0 -0
- package/dist/standalone/assets/{heavy-fields-aI_gOI6-.js.map → heavy-fields-ZuqfOFMv.js.map} +1 -1
- package/dist/standalone/assets/home-page-HmheewiP.js +3 -0
- package/dist/standalone/assets/home-page-HmheewiP.js.br +0 -0
- package/dist/standalone/assets/home-page-HmheewiP.js.gz +0 -0
- package/dist/standalone/assets/{home-page-Xc7HK72H.js.map → home-page-HmheewiP.js.map} +1 -1
- package/dist/standalone/assets/icon-registry-BV44--RL.js +2 -0
- package/dist/standalone/assets/icon-registry-BV44--RL.js.br +0 -0
- package/dist/standalone/assets/icon-registry-BV44--RL.js.gz +0 -0
- package/dist/standalone/assets/icon-registry-BV44--RL.js.map +1 -0
- package/dist/standalone/assets/{index-OvloY2cG.css → index-95cwJ2RY.css} +1 -1
- package/dist/standalone/assets/index-95cwJ2RY.css.br +0 -0
- package/dist/standalone/assets/index-95cwJ2RY.css.gz +0 -0
- package/dist/standalone/assets/index-t4woXGa-.js +15 -0
- package/dist/standalone/assets/index-t4woXGa-.js.br +0 -0
- package/dist/standalone/assets/index-t4woXGa-.js.gz +0 -0
- package/dist/standalone/assets/index-t4woXGa-.js.map +1 -0
- package/dist/standalone/assets/json-editor-sGw4fDoj.js +2 -0
- package/dist/standalone/assets/json-editor-sGw4fDoj.js.br +0 -0
- package/dist/standalone/assets/json-editor-sGw4fDoj.js.gz +0 -0
- package/dist/standalone/assets/{json-editor-DuYj4QGx.js.map → json-editor-sGw4fDoj.js.map} +1 -1
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js +7 -0
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js.br +0 -0
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js.gz +0 -0
- package/dist/standalone/assets/property-renderer-DyCwdVkh.js.map +1 -0
- package/dist/standalone/assets/reference-Dfd804y3.js +2 -0
- package/dist/standalone/assets/reference-Dfd804y3.js.br +0 -0
- package/dist/standalone/assets/reference-Dfd804y3.js.gz +0 -0
- package/dist/standalone/assets/{reference-CbtDQb7U.js.map → reference-Dfd804y3.js.map} +1 -1
- package/dist/standalone/assets/refresh-cw-DHvUQTMb.js +2 -0
- package/dist/standalone/assets/refresh-cw-DHvUQTMb.js.map +1 -0
- package/dist/standalone/assets/revisions-button-DXZAh2Lu.js +2 -0
- package/dist/standalone/assets/revisions-button-DXZAh2Lu.js.br +0 -0
- package/dist/standalone/assets/revisions-button-DXZAh2Lu.js.gz +0 -0
- package/dist/standalone/assets/{revisions-button-hLRZGkwM.js.map → revisions-button-DXZAh2Lu.js.map} +1 -1
- package/dist/standalone/assets/router-wFvtgo77.js +186 -0
- package/dist/standalone/assets/router-wFvtgo77.js.br +0 -0
- package/dist/standalone/assets/router-wFvtgo77.js.gz +0 -0
- package/dist/standalone/assets/router-wFvtgo77.js.map +1 -0
- package/dist/standalone/assets/select-BWf6walM.js +2 -0
- package/dist/standalone/assets/select-BWf6walM.js.br +0 -0
- package/dist/standalone/assets/select-BWf6walM.js.gz +0 -0
- package/dist/standalone/assets/{select-BxTIWCco.js.map → select-BWf6walM.js.map} +1 -1
- package/dist/standalone/assets/settings-page-Co7sWbbL.js +2 -0
- package/dist/standalone/assets/settings-page-Co7sWbbL.js.br +0 -0
- package/dist/standalone/assets/settings-page-Co7sWbbL.js.gz +0 -0
- package/dist/standalone/assets/{settings-page-FHzVUo4t.js.map → settings-page-Co7sWbbL.js.map} +1 -1
- package/dist/standalone/assets/show-page-D-_vldWV.js +2 -0
- package/dist/standalone/assets/show-page-D-_vldWV.js.br +0 -0
- package/dist/standalone/assets/show-page-D-_vldWV.js.gz +0 -0
- package/dist/standalone/assets/show-page-D-_vldWV.js.map +1 -0
- package/dist/standalone/assets/{tabs-BrnwAET7.js → tabs-khcHka8W.js} +2 -2
- package/dist/standalone/assets/tabs-khcHka8W.js.br +0 -0
- package/dist/standalone/assets/tabs-khcHka8W.js.gz +0 -0
- package/dist/standalone/assets/{tabs-BrnwAET7.js.map → tabs-khcHka8W.js.map} +1 -1
- package/dist/standalone/assets/{zap-Be2c7_cs.js → upload-BVhXhZgn.js} +2 -2
- package/dist/standalone/assets/upload-BVhXhZgn.js.br +0 -0
- package/dist/standalone/assets/upload-BVhXhZgn.js.gz +0 -0
- package/dist/standalone/assets/upload-BVhXhZgn.js.map +1 -0
- package/dist/standalone/assets/{useQueries-CX5Gh6HV.js → useQueries-BCUhWYX4.js} +2 -2
- package/dist/standalone/assets/useQueries-BCUhWYX4.js.br +0 -0
- package/dist/standalone/assets/useQueries-BCUhWYX4.js.gz +0 -0
- package/dist/standalone/assets/{useQueries-CX5Gh6HV.js.map → useQueries-BCUhWYX4.js.map} +1 -1
- package/dist/standalone/assets/{user-directory-ZxAjN_q9.js → user-directory-9COoW6AO.js} +2 -2
- package/dist/standalone/assets/user-directory-9COoW6AO.js.br +0 -0
- package/dist/standalone/assets/user-directory-9COoW6AO.js.gz +0 -0
- package/dist/standalone/assets/{user-directory-ZxAjN_q9.js.map → user-directory-9COoW6AO.js.map} +1 -1
- package/dist/standalone/assets/{value-format-DmXCSwLn.js → value-format-CPnbnlE6.js} +2 -2
- package/dist/standalone/assets/value-format-CPnbnlE6.js.br +0 -0
- package/dist/standalone/assets/value-format-CPnbnlE6.js.gz +0 -0
- package/dist/standalone/assets/{value-format-DmXCSwLn.js.map → value-format-CPnbnlE6.js.map} +1 -1
- package/dist/standalone/assets/wand-sparkles-DWaFQeYS.js +2 -0
- package/dist/standalone/assets/wand-sparkles-DWaFQeYS.js.map +1 -0
- package/dist/standalone/assets/wizard-create-page-CFwMs8E3.js +2 -0
- package/dist/standalone/assets/wizard-create-page-CFwMs8E3.js.br +0 -0
- package/dist/standalone/assets/wizard-create-page-CFwMs8E3.js.gz +0 -0
- package/dist/standalone/assets/{wizard-create-page-Rh4uWxUR.js.map → wizard-create-page-CFwMs8E3.js.map} +1 -1
- package/dist/standalone/assets/zap-b3saQVKc.js +2 -0
- package/dist/standalone/assets/zap-b3saQVKc.js.map +1 -0
- package/dist/standalone/assets/{zod-bSPpBhsj.js → zod-BbfEBA4A.js} +2 -2
- package/dist/standalone/assets/zod-BbfEBA4A.js.br +0 -0
- package/dist/standalone/assets/zod-BbfEBA4A.js.gz +0 -0
- package/dist/standalone/assets/{zod-bSPpBhsj.js.map → zod-BbfEBA4A.js.map} +1 -1
- package/dist/standalone/index.html +8 -8
- package/dist/standalone/index.html.br +0 -0
- package/dist/standalone/index.html.gz +0 -0
- package/package.json +5 -5
- package/dist/standalone/assets/ai-assistant-widget-Dk-VvXD0.js.br +0 -0
- package/dist/standalone/assets/ai-assistant-widget-Dk-VvXD0.js.gz +0 -0
- package/dist/standalone/assets/audit-log-page-BEC79lKy.js +0 -2
- package/dist/standalone/assets/audit-log-page-BEC79lKy.js.br +0 -0
- package/dist/standalone/assets/audit-log-page-BEC79lKy.js.gz +0 -0
- package/dist/standalone/assets/calendar-Pq7dP9RH.js.br +0 -0
- package/dist/standalone/assets/calendar-Pq7dP9RH.js.gz +0 -0
- package/dist/standalone/assets/chart-widget-B7pIeDCP.js +0 -2
- package/dist/standalone/assets/chart-widget-B7pIeDCP.js.br +0 -0
- package/dist/standalone/assets/chart-widget-B7pIeDCP.js.gz +0 -0
- package/dist/standalone/assets/command-B6-wRF2R.js.br +0 -0
- package/dist/standalone/assets/command-B6-wRF2R.js.gz +0 -0
- package/dist/standalone/assets/date-picker-BAp85mMa.js.br +0 -0
- package/dist/standalone/assets/date-picker-BAp85mMa.js.gz +0 -0
- package/dist/standalone/assets/dist-CvKz-wgE.js.br +0 -0
- package/dist/standalone/assets/dist-CvKz-wgE.js.gz +0 -0
- package/dist/standalone/assets/dist-CvKz-wgE.js.map +0 -1
- package/dist/standalone/assets/dist-Dkym1-ts.js.br +0 -0
- package/dist/standalone/assets/dist-Dkym1-ts.js.gz +0 -0
- package/dist/standalone/assets/edit-page-BVwML9yD.js +0 -2
- package/dist/standalone/assets/edit-page-BVwML9yD.js.br +0 -0
- package/dist/standalone/assets/edit-page-BVwML9yD.js.gz +0 -0
- package/dist/standalone/assets/empty-BmE-qyE9.js.br +0 -0
- package/dist/standalone/assets/empty-BmE-qyE9.js.gz +0 -0
- package/dist/standalone/assets/global-search-dialog-C3Ri2VRv.js +0 -2
- package/dist/standalone/assets/global-search-dialog-C3Ri2VRv.js.br +0 -0
- package/dist/standalone/assets/global-search-dialog-C3Ri2VRv.js.gz +0 -0
- package/dist/standalone/assets/heavy-fields-aI_gOI6-.js.br +0 -0
- package/dist/standalone/assets/heavy-fields-aI_gOI6-.js.gz +0 -0
- package/dist/standalone/assets/home-page-Xc7HK72H.js +0 -3
- package/dist/standalone/assets/home-page-Xc7HK72H.js.br +0 -0
- package/dist/standalone/assets/home-page-Xc7HK72H.js.gz +0 -0
- package/dist/standalone/assets/icon-registry-AlRIE8PQ.js +0 -2
- package/dist/standalone/assets/icon-registry-AlRIE8PQ.js.br +0 -0
- package/dist/standalone/assets/icon-registry-AlRIE8PQ.js.gz +0 -0
- package/dist/standalone/assets/icon-registry-AlRIE8PQ.js.map +0 -1
- package/dist/standalone/assets/index-OvloY2cG.css.br +0 -0
- package/dist/standalone/assets/index-OvloY2cG.css.gz +0 -0
- package/dist/standalone/assets/index-R1VJOHqq.js +0 -15
- package/dist/standalone/assets/index-R1VJOHqq.js.br +0 -0
- package/dist/standalone/assets/index-R1VJOHqq.js.gz +0 -0
- package/dist/standalone/assets/index-R1VJOHqq.js.map +0 -1
- package/dist/standalone/assets/json-editor-DuYj4QGx.js +0 -2
- package/dist/standalone/assets/json-editor-DuYj4QGx.js.br +0 -0
- package/dist/standalone/assets/json-editor-DuYj4QGx.js.gz +0 -0
- package/dist/standalone/assets/property-renderer-U2F_u1LG.js +0 -7
- package/dist/standalone/assets/property-renderer-U2F_u1LG.js.br +0 -0
- package/dist/standalone/assets/property-renderer-U2F_u1LG.js.gz +0 -0
- package/dist/standalone/assets/property-renderer-U2F_u1LG.js.map +0 -1
- package/dist/standalone/assets/reference-CbtDQb7U.js +0 -2
- package/dist/standalone/assets/reference-CbtDQb7U.js.br +0 -0
- package/dist/standalone/assets/reference-CbtDQb7U.js.gz +0 -0
- package/dist/standalone/assets/refresh-cw-B2G7AzZh.js +0 -2
- package/dist/standalone/assets/refresh-cw-B2G7AzZh.js.map +0 -1
- package/dist/standalone/assets/revisions-button-hLRZGkwM.js +0 -2
- package/dist/standalone/assets/revisions-button-hLRZGkwM.js.br +0 -0
- package/dist/standalone/assets/revisions-button-hLRZGkwM.js.gz +0 -0
- package/dist/standalone/assets/router-DmBe_NWn.js +0 -186
- package/dist/standalone/assets/router-DmBe_NWn.js.br +0 -0
- package/dist/standalone/assets/router-DmBe_NWn.js.gz +0 -0
- package/dist/standalone/assets/router-DmBe_NWn.js.map +0 -1
- package/dist/standalone/assets/select-BxTIWCco.js +0 -2
- package/dist/standalone/assets/select-BxTIWCco.js.br +0 -0
- package/dist/standalone/assets/select-BxTIWCco.js.gz +0 -0
- package/dist/standalone/assets/settings-page-FHzVUo4t.js +0 -2
- package/dist/standalone/assets/settings-page-FHzVUo4t.js.br +0 -0
- package/dist/standalone/assets/settings-page-FHzVUo4t.js.gz +0 -0
- package/dist/standalone/assets/show-page-Jotfue76.js +0 -2
- package/dist/standalone/assets/show-page-Jotfue76.js.br +0 -0
- package/dist/standalone/assets/show-page-Jotfue76.js.gz +0 -0
- package/dist/standalone/assets/show-page-Jotfue76.js.map +0 -1
- package/dist/standalone/assets/tabs-BrnwAET7.js.br +0 -0
- package/dist/standalone/assets/tabs-BrnwAET7.js.gz +0 -0
- package/dist/standalone/assets/useQueries-CX5Gh6HV.js.br +0 -0
- package/dist/standalone/assets/useQueries-CX5Gh6HV.js.gz +0 -0
- package/dist/standalone/assets/user-directory-ZxAjN_q9.js.br +0 -0
- package/dist/standalone/assets/user-directory-ZxAjN_q9.js.gz +0 -0
- package/dist/standalone/assets/value-format-DmXCSwLn.js.br +0 -0
- package/dist/standalone/assets/value-format-DmXCSwLn.js.gz +0 -0
- package/dist/standalone/assets/wand-sparkles-BDM69Lk9.js +0 -2
- package/dist/standalone/assets/wand-sparkles-BDM69Lk9.js.map +0 -1
- package/dist/standalone/assets/wizard-create-page-Rh4uWxUR.js +0 -2
- package/dist/standalone/assets/wizard-create-page-Rh4uWxUR.js.br +0 -0
- package/dist/standalone/assets/wizard-create-page-Rh4uWxUR.js.gz +0 -0
- package/dist/standalone/assets/zap-Be2c7_cs.js.br +0 -0
- package/dist/standalone/assets/zap-Be2c7_cs.js.gz +0 -0
- package/dist/standalone/assets/zap-Be2c7_cs.js.map +0 -1
- package/dist/standalone/assets/zod-bSPpBhsj.js.br +0 -0
- package/dist/standalone/assets/zod-bSPpBhsj.js.gz +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,n as t}from"./createLucideIcon-CUopU_LC.js";import{S as n,s as r}from"./with-selector-NDLhu4dT.js";import{t as i}from"./chevrons-up-down-BHCs46XQ.js";import{n as a}from"./pencil-BO-k3yTG.js";import{t as o}from"./x-C3kLunD6.js";import{s}from"./dist-Dpg8xy_r.js";import{K as c,Y as l,et as u,n as d,ot as f,rt as p}from"./router-wFvtgo77.js";import{a as m,i as h,n as g,t as _}from"./useQueries-BCUhWYX4.js";import{t as v}from"./badge-6nyM5Jft.js";import{a as y,i as b,o as x,r as S,s as C,t as w}from"./command-BNF_evMy.js";import{yt as T}from"./index-t4woXGa-.js";var E=e(t(),1),D=n();function O({resourceId:e,recordId:t,fallback:n,showIcon:i=!1,className:o,populated:s}){let l=p(),u=t==null?``:String(t),m=!!(u&&s&&s.title),h=c(e),g=h===void 0||h.actions.some(e=>e.name===`show`),{data:_}=f({queryKey:[`modern-admin`,e,`show`,u],queryFn:()=>l.show(e,u),enabled:!!u&&!m&&g,staleTime:3e4});if(!u)return n??null;let y=(m?s.title:_?.record?.title)||`#${u}`;return g?(0,D.jsxs)(d,{to:{name:`show`,resourceId:e,recordId:u},className:r(`inline-flex items-center gap-1 hover:underline`,o),onClick:e=>e.stopPropagation(),children:[(0,D.jsx)(v,{variant:`secondary`,children:y}),i&&(0,D.jsx)(a,{className:`size-3 opacity-50`})]}):(0,D.jsx)(`span`,{className:r(`inline-flex items-center`,o),children:(0,D.jsx)(v,{variant:`secondary`,children:y})})}function k({referenceResourceId:e,value:t,onChange:n,disabled:a,placeholder:o,className:c}){let[d,_]=E.useState(!1),[v,O]=E.useState(``),k=M(v,250),A=p(),{t:j}=u(),N=o??j(`common:select`),P=f({queryKey:[`modern-admin`,e,`show`,t],queryFn:()=>A.show(e,String(t)),enabled:t!=null&&t!==``,staleTime:3e4}),F=l(e,k,d),I=F.data?.records??[],L=P.data?.record?.title,R=L?`${L} <${t}>`:t!=null&&t!==``?`#${t}`:``;return(0,D.jsxs)(g,{open:d,onOpenChange:_,children:[(0,D.jsx)(m,{asChild:!0,children:(0,D.jsxs)(s,{variant:`outline`,role:`combobox`,"aria-expanded":d,disabled:a,className:r(`w-full justify-between font-normal`,c),children:[(0,D.jsx)(`span`,{className:r(`truncate`,!R&&`text-muted-foreground`),title:R||void 0,children:R||N}),(0,D.jsx)(i,{className:`size-4 shrink-0 opacity-50`})]})}),(0,D.jsx)(h,{className:`w-[var(--radix-popover-trigger-width)] p-0`,align:`start`,children:(0,D.jsxs)(w,{shouldFilter:!1,children:[(0,D.jsx)(y,{placeholder:j(`common:searchPlaceholder`),value:v,onValueChange:O}),(0,D.jsxs)(C,{children:[F.isLoading&&(0,D.jsx)(`div`,{className:`p-3 text-sm text-muted-foreground`,children:j(`common:loading`)}),!F.isLoading&&I.length===0&&(0,D.jsx)(S,{children:j(`common:noRecords`)}),t!=null&&t!==``&&(0,D.jsx)(b,{children:(0,D.jsxs)(x,{onSelect:()=>{n(null),_(!1)},children:[(0,D.jsx)(T,{className:`size-4 opacity-0`}),(0,D.jsx)(`span`,{className:`text-muted-foreground`,children:j(`common:clearSelection`)})]})}),(0,D.jsx)(b,{children:I.map(e=>{let i=String(e.id)===String(t??``);return(0,D.jsxs)(x,{value:e.id,onSelect:()=>{n(e.id),_(!1)},children:[(0,D.jsx)(T,{className:r(`size-4`,i?`opacity-100`:`opacity-0`)}),(0,D.jsx)(`span`,{className:`truncate`,title:e.title?`${e.title} <${e.id}>`:`#${e.id}`,children:e.title?`${e.title} <${e.id}>`:`#${e.id}`})]},e.id)})})]})]})})]})}function A({resourceId:e,recordIds:t,className:n,populated:i,populatedKeyPrefix:a}){return!t||t.length===0?(0,D.jsx)(`span`,{className:`text-muted-foreground`,children:`—`}):(0,D.jsx)(`div`,{className:r(`flex flex-wrap gap-1`,n),children:t.map(t=>(0,D.jsx)(O,{resourceId:e,recordId:t,populated:i&&a?i[`${a}.${t}`]:void 0},String(t)))})}function j({referenceResourceId:e,value:t,onChange:n,disabled:a,placeholder:c}){let[d,f]=E.useState(!1),[O,k]=E.useState(``),A=M(O,250),j=p(),{t:N}=u(),P=c??N(`common:select`),F=E.useMemo(()=>(t??[]).map(String),[t]),I=_({queries:F.map(t=>({queryKey:[`modern-admin`,e,`show`,t],queryFn:()=>j.show(e,t),staleTime:3e4}))}),L=E.useMemo(()=>F.map((e,t)=>{let n=I[t]?.data?.record?.title;return{id:e,title:n?`${n} <${e}>`:`#${e}`}}),[F,I]),R=l(e,A,d),z=R.data?.records??[],B=e=>{let t=String(e);n(F.includes(t)?F.filter(e=>e!==t):[...F,t])},V=e=>{n(F.filter(t=>t!==e))};return(0,D.jsxs)(`div`,{className:`space-y-2`,children:[L.length>0&&(0,D.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:L.map(e=>(0,D.jsxs)(v,{variant:`secondary`,className:`gap-1 pr-1`,children:[e.title,(0,D.jsx)(`button`,{type:`button`,"aria-label":N(`common:removeItem`,{title:e.title}),disabled:a,onClick:()=>V(e.id),className:`rounded-sm opacity-60 hover:opacity-100`,children:(0,D.jsx)(o,{className:`size-3`})})]},e.id))}),(0,D.jsxs)(g,{open:d,onOpenChange:f,children:[(0,D.jsx)(m,{asChild:!0,children:(0,D.jsxs)(s,{variant:`outline`,role:`combobox`,"aria-expanded":d,disabled:a,className:`w-full justify-between font-normal`,children:[(0,D.jsx)(`span`,{className:`truncate text-muted-foreground`,children:F.length>0?N(`common:nSelectedAddMore`,{count:F.length}):P}),(0,D.jsx)(i,{className:`size-4 shrink-0 opacity-50`})]})}),(0,D.jsx)(h,{className:`w-[var(--radix-popover-trigger-width)] p-0`,align:`start`,children:(0,D.jsxs)(w,{shouldFilter:!1,children:[(0,D.jsx)(y,{placeholder:N(`common:searchPlaceholder`),value:O,onValueChange:k}),(0,D.jsxs)(C,{children:[R.isLoading&&(0,D.jsx)(`div`,{className:`p-3 text-sm text-muted-foreground`,children:N(`common:loading`)}),!R.isLoading&&z.length===0&&(0,D.jsx)(S,{children:N(`common:noRecords`)}),(0,D.jsx)(b,{children:z.map(e=>{let t=F.includes(String(e.id));return(0,D.jsxs)(x,{value:String(e.id),onSelect:()=>B(e.id),children:[(0,D.jsx)(T,{className:r(`size-4`,t?`opacity-100`:`opacity-0`)}),(0,D.jsx)(`span`,{className:`truncate`,title:e.title?`${e.title} <${e.id}>`:`#${e.id}`,children:e.title?`${e.title} <${e.id}>`:`#${e.id}`})]},e.id)})})]})]})})]})]})}var M=(e,t)=>{let[n,r]=E.useState(e);return E.useEffect(()=>{let n=setTimeout(()=>r(e),t);return()=>clearTimeout(n)},[e,t]),n};export{j as i,O as n,A as r,k as t};
|
|
2
|
+
//# sourceMappingURL=reference-Dfd804y3.js.map
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference-CbtDQb7U.js","names":[],"sources":["../../../../react/src/reference.tsx"],"sourcesContent":["// Reference-field helpers. Three surfaces:\n// - <ReferenceLink>: read-only display (list/show views) — fetches the\n// referenced record's title and renders it as a hyperlink to its show page.\n// - <ReferenceCombobox>: single-value edit control — Command-driven popover\n// with live search against the referenced resource's `search` action.\n// - <ReferenceMultiCombobox>: multi-value variant for many-to-many fields\n// (an array of foreign IDs); selected items render as removable chips.\n\nimport * as React from 'react'\nimport {\n Badge,\n Button,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Popover,\n PopoverContent,\n PopoverTrigger,\n cn,\n} from '@modern-admin/ui'\nimport { Check, ChevronsUpDown, ExternalLink, X } from 'lucide-react'\nimport { useQueries, useQuery } from '@tanstack/react-query'\nimport { useAdminClient } from './provider.js'\nimport { useResource, useSearchRecords } from './hooks.js'\nimport { useI18n } from './i18n.js'\nimport { Link } from './router.js'\n\n/** Read-only badge that links to the referenced record's show page.\n *\n * When `populated` is provided (e.g. supplied by the list/show endpoint via\n * `record.populated[propertyPath]`) the title is rendered directly from it\n * and no `show` request is fired — this is what prevents the N+1 fetch\n * storm on list pages with reference columns. */\nexport function ReferenceLink({\n resourceId,\n recordId,\n fallback,\n showIcon = false,\n className,\n populated,\n}: {\n resourceId: string\n recordId: string | number | null | undefined\n fallback?: React.ReactNode\n showIcon?: boolean\n className?: string\n populated?: { id?: string; title?: string } | null\n}): React.ReactElement | null {\n const client = useAdminClient()\n const id = recordId == null ? '' : String(recordId)\n const hasPopulated = !!(id && populated && populated.title)\n const referencedResource = useResource(resourceId)\n // When the SPA config has been loaded, its `actions` list is already\n // filtered against the current admin's access. Missing `show` = no\n // permission to view the referenced record → render plain text instead\n // of a clickable link. While the config is still loading (`undefined`)\n // we default to \"linkable\" so the first paint matches the steady state\n // for the common case.\n const canShow =\n referencedResource === undefined\n ? true\n : referencedResource.actions.some((a) => a.name === 'show')\n const { data } = useQuery({\n queryKey: ['modern-admin', resourceId, 'show', id],\n queryFn: () => client.show(resourceId, id),\n enabled: !!id && !hasPopulated && canShow,\n staleTime: 30_000,\n })\n if (!id) return (fallback as React.ReactElement | null) ?? null\n const title = (hasPopulated ? populated!.title : data?.record?.title) || `#${id}`\n if (!canShow) {\n return (\n <span className={cn('inline-flex items-center', className)}>\n <Badge variant=\"secondary\">{title}</Badge>\n </span>\n )\n }\n return (\n <Link\n to={{ name: 'show', resourceId, recordId: id }}\n className={cn('inline-flex items-center gap-1 hover:underline', className)}\n onClick={(e) => e.stopPropagation()}\n >\n <Badge variant=\"secondary\">{title}</Badge>\n {showIcon && <ExternalLink className=\"size-3 opacity-50\" />}\n </Link>\n )\n}\n\n/** Combobox bound to a referenced resource's `search` action. */\nexport function ReferenceCombobox({\n referenceResourceId,\n value,\n onChange,\n disabled,\n placeholder,\n className,\n}: {\n referenceResourceId: string\n value: string | number | null | undefined\n onChange(next: string | null): void\n disabled?: boolean\n placeholder?: string\n /** Extra classes applied to the trigger button (e.g. height override). */\n className?: string\n}): React.ReactElement {\n const [open, setOpen] = React.useState(false)\n const [query, setQuery] = React.useState('')\n const debounced = useDebounced(query, 250)\n const client = useAdminClient()\n const { t } = useI18n()\n const resolvedPlaceholder = placeholder ?? t('common:select')\n\n // The currently-selected record (loaded once for the trigger label).\n const selected = useQuery({\n queryKey: ['modern-admin', referenceResourceId, 'show', value],\n queryFn: () => client.show(referenceResourceId, String(value)),\n enabled: value != null && value !== '',\n staleTime: 30_000,\n })\n\n const search = useSearchRecords(referenceResourceId, debounced, open)\n const items = search.data?.records ?? []\n\n const _title = selected.data?.record?.title\n const selectedLabel =\n _title\n ? `${_title} <${value}>`\n : value != null && value !== ''\n ? `#${value}`\n : ''\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled}\n className={cn('w-full justify-between font-normal', className)}\n >\n <span\n className={cn('truncate', !selectedLabel && 'text-muted-foreground')}\n title={selectedLabel || undefined}\n >\n {selectedLabel || resolvedPlaceholder}\n </span>\n <ChevronsUpDown className=\"size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[var(--radix-popover-trigger-width)] p-0\" align=\"start\">\n <Command shouldFilter={false}>\n <CommandInput\n placeholder={t('common:searchPlaceholder')}\n value={query}\n onValueChange={setQuery}\n />\n <CommandList>\n {search.isLoading && <div className=\"p-3 text-sm text-muted-foreground\">{t('common:loading')}</div>}\n {!search.isLoading && items.length === 0 && (\n <CommandEmpty>{t('common:noRecords')}</CommandEmpty>\n )}\n {value != null && value !== '' && (\n <CommandGroup>\n <CommandItem\n onSelect={() => {\n onChange(null)\n setOpen(false)\n }}\n >\n <Check className=\"size-4 opacity-0\" />\n <span className=\"text-muted-foreground\">{t('common:clearSelection')}</span>\n </CommandItem>\n </CommandGroup>\n )}\n <CommandGroup>\n {items.map((r) => {\n const isSelected = String(r.id) === String(value ?? '')\n return (\n <CommandItem\n key={r.id}\n value={r.id}\n onSelect={() => {\n onChange(r.id)\n setOpen(false)\n }}\n >\n <Check className={cn('size-4', isSelected ? 'opacity-100' : 'opacity-0')} />\n <span className=\"truncate\" title={r.title ? `${r.title} <${r.id}>` : `#${r.id}`}>\n {r.title ? `${r.title} <${r.id}>` : `#${r.id}`}\n </span>\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n\n/** Renders a list of comma-separated badge links, one per foreign key.\n *\n * When `populated` + `populatedKeyPrefix` are provided, each item is looked up\n * via `populated[`${prefix}.${id}`]` and threaded into its `<ReferenceLink>`\n * to suppress per-row `show` requests. The key shape matches what the m2m\n * feature's read-hook writes (see `packages/feature-m2m`) and what the list\n * action's `populateReferences` helper writes for array references. */\nexport function ReferenceLinkList({\n resourceId,\n recordIds,\n className,\n populated,\n populatedKeyPrefix,\n}: {\n resourceId: string\n recordIds: ReadonlyArray<string | number>\n className?: string\n populated?: Record<string, unknown>\n populatedKeyPrefix?: string\n}): React.ReactElement {\n if (!recordIds || recordIds.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n return (\n <div className={cn('flex flex-wrap gap-1', className)}>\n {recordIds.map((id) => {\n const entry =\n populated && populatedKeyPrefix\n ? (populated[`${populatedKeyPrefix}.${id}`] as\n | { id?: string; title?: string }\n | undefined)\n : undefined\n return (\n <ReferenceLink\n key={String(id)}\n resourceId={resourceId}\n recordId={id}\n populated={entry}\n />\n )\n })}\n </div>\n )\n}\n\n/** Multi-select combobox for many-to-many references. Renders selected items\n * as removable chips and feeds search results into a checkable command list. */\nexport function ReferenceMultiCombobox({\n referenceResourceId,\n value,\n onChange,\n disabled,\n placeholder,\n}: {\n referenceResourceId: string\n value: ReadonlyArray<string | number> | null | undefined\n onChange(next: Array<string | number>): void\n disabled?: boolean\n placeholder?: string\n}): React.ReactElement {\n const [open, setOpen] = React.useState(false)\n const [query, setQuery] = React.useState('')\n const debounced = useDebounced(query, 250)\n const client = useAdminClient()\n const { t } = useI18n()\n const resolvedPlaceholder = placeholder ?? t('common:select')\n const ids = React.useMemo(() => (value ?? []).map(String), [value])\n\n // Resolve labels per-id so adding/removing one item only fetches the new\n // one. Sharing the cache key with <ReferenceLink>'s single-record query\n // means already-known titles render instantly without flicker.\n const titleQueries = useQueries({\n queries: ids.map((id) => ({\n queryKey: ['modern-admin', referenceResourceId, 'show', id],\n queryFn: () => client.show(referenceResourceId, id),\n staleTime: 30_000,\n })),\n })\n const chips = React.useMemo(\n () =>\n ids.map((id, i) => {\n const t = titleQueries[i]?.data?.record?.title\n return { id, title: t ? `${t} <${id}>` : `#${id}` }\n }),\n [ids, titleQueries],\n )\n\n const search = useSearchRecords(referenceResourceId, debounced, open)\n const items = search.data?.records ?? []\n\n const toggle = (id: string | number): void => {\n const sid = String(id)\n const next = ids.includes(sid) ? ids.filter((x) => x !== sid) : [...ids, sid]\n onChange(next)\n }\n\n const remove = (id: string): void => {\n onChange(ids.filter((x) => x !== id))\n }\n\n return (\n <div className=\"space-y-2\">\n {chips.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {chips.map((s) => (\n <Badge key={s.id} variant=\"secondary\" className=\"gap-1 pr-1\">\n {s.title}\n <button\n type=\"button\"\n aria-label={t('common:removeItem', { title: s.title })}\n disabled={disabled}\n onClick={() => remove(s.id)}\n className=\"rounded-sm opacity-60 hover:opacity-100\"\n >\n <X className=\"size-3\" />\n </button>\n </Badge>\n ))}\n </div>\n )}\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled}\n className=\"w-full justify-between font-normal\"\n >\n <span className=\"truncate text-muted-foreground\">\n {ids.length > 0 ? t('common:nSelectedAddMore', { count: ids.length }) : resolvedPlaceholder}\n </span>\n <ChevronsUpDown className=\"size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[var(--radix-popover-trigger-width)] p-0\" align=\"start\">\n <Command shouldFilter={false}>\n <CommandInput placeholder={t('common:searchPlaceholder')} value={query} onValueChange={setQuery} />\n <CommandList>\n {search.isLoading && (\n <div className=\"p-3 text-sm text-muted-foreground\">{t('common:loading')}</div>\n )}\n {!search.isLoading && items.length === 0 && (\n <CommandEmpty>{t('common:noRecords')}</CommandEmpty>\n )}\n <CommandGroup>\n {items.map((r) => {\n const isSelected = ids.includes(String(r.id))\n return (\n <CommandItem\n key={r.id}\n value={String(r.id)}\n onSelect={() => toggle(r.id)}\n >\n <Check\n className={cn('size-4', isSelected ? 'opacity-100' : 'opacity-0')}\n />\n <span className=\"truncate\" title={r.title ? `${r.title} <${r.id}>` : `#${r.id}`}>\n {r.title ? `${r.title} <${r.id}>` : `#${r.id}`}\n </span>\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n )\n}\n\nconst useDebounced = <T,>(value: T, ms: number): T => {\n const [v, setV] = React.useState(value)\n React.useEffect(() => {\n const id = setTimeout(() => setV(value), ms)\n return () => clearTimeout(id)\n }, [value, ms])\n return v\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reference-Dfd804y3.js","names":[],"sources":["../../../../react/src/reference.tsx"],"sourcesContent":["// Reference-field helpers. Three surfaces:\n// - <ReferenceLink>: read-only display (list/show views) — fetches the\n// referenced record's title and renders it as a hyperlink to its show page.\n// - <ReferenceCombobox>: single-value edit control — Command-driven popover\n// with live search against the referenced resource's `search` action.\n// - <ReferenceMultiCombobox>: multi-value variant for many-to-many fields\n// (an array of foreign IDs); selected items render as removable chips.\n\nimport * as React from 'react'\nimport {\n Badge,\n Button,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Popover,\n PopoverContent,\n PopoverTrigger,\n cn,\n} from '@modern-admin/ui'\nimport { Check, ChevronsUpDown, ExternalLink, X } from 'lucide-react'\nimport { useQueries, useQuery } from '@tanstack/react-query'\nimport { useAdminClient } from './provider.js'\nimport { useResource, useSearchRecords } from './hooks.js'\nimport { useI18n } from './i18n.js'\nimport { Link } from './router.js'\n\n/** Read-only badge that links to the referenced record's show page.\n *\n * When `populated` is provided (e.g. supplied by the list/show endpoint via\n * `record.populated[propertyPath]`) the title is rendered directly from it\n * and no `show` request is fired — this is what prevents the N+1 fetch\n * storm on list pages with reference columns. */\nexport function ReferenceLink({\n resourceId,\n recordId,\n fallback,\n showIcon = false,\n className,\n populated,\n}: {\n resourceId: string\n recordId: string | number | null | undefined\n fallback?: React.ReactNode\n showIcon?: boolean\n className?: string\n populated?: { id?: string; title?: string } | null\n}): React.ReactElement | null {\n const client = useAdminClient()\n const id = recordId == null ? '' : String(recordId)\n const hasPopulated = !!(id && populated && populated.title)\n const referencedResource = useResource(resourceId)\n // When the SPA config has been loaded, its `actions` list is already\n // filtered against the current admin's access. Missing `show` = no\n // permission to view the referenced record → render plain text instead\n // of a clickable link. While the config is still loading (`undefined`)\n // we default to \"linkable\" so the first paint matches the steady state\n // for the common case.\n const canShow =\n referencedResource === undefined\n ? true\n : referencedResource.actions.some((a) => a.name === 'show')\n const { data } = useQuery({\n queryKey: ['modern-admin', resourceId, 'show', id],\n queryFn: () => client.show(resourceId, id),\n enabled: !!id && !hasPopulated && canShow,\n staleTime: 30_000,\n })\n if (!id) return (fallback as React.ReactElement | null) ?? null\n const title = (hasPopulated ? populated!.title : data?.record?.title) || `#${id}`\n if (!canShow) {\n return (\n <span className={cn('inline-flex items-center', className)}>\n <Badge variant=\"secondary\">{title}</Badge>\n </span>\n )\n }\n return (\n <Link\n to={{ name: 'show', resourceId, recordId: id }}\n className={cn('inline-flex items-center gap-1 hover:underline', className)}\n onClick={(e) => e.stopPropagation()}\n >\n <Badge variant=\"secondary\">{title}</Badge>\n {showIcon && <ExternalLink className=\"size-3 opacity-50\" />}\n </Link>\n )\n}\n\n/** Combobox bound to a referenced resource's `search` action. */\nexport function ReferenceCombobox({\n referenceResourceId,\n value,\n onChange,\n disabled,\n placeholder,\n className,\n}: {\n referenceResourceId: string\n value: string | number | null | undefined\n onChange(next: string | null): void\n disabled?: boolean\n placeholder?: string\n /** Extra classes applied to the trigger button (e.g. height override). */\n className?: string\n}): React.ReactElement {\n const [open, setOpen] = React.useState(false)\n const [query, setQuery] = React.useState('')\n const debounced = useDebounced(query, 250)\n const client = useAdminClient()\n const { t } = useI18n()\n const resolvedPlaceholder = placeholder ?? t('common:select')\n\n // The currently-selected record (loaded once for the trigger label).\n const selected = useQuery({\n queryKey: ['modern-admin', referenceResourceId, 'show', value],\n queryFn: () => client.show(referenceResourceId, String(value)),\n enabled: value != null && value !== '',\n staleTime: 30_000,\n })\n\n const search = useSearchRecords(referenceResourceId, debounced, open)\n const items = search.data?.records ?? []\n\n const _title = selected.data?.record?.title\n const selectedLabel =\n _title\n ? `${_title} <${value}>`\n : value != null && value !== ''\n ? `#${value}`\n : ''\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled}\n className={cn('w-full justify-between font-normal', className)}\n >\n <span\n className={cn('truncate', !selectedLabel && 'text-muted-foreground')}\n title={selectedLabel || undefined}\n >\n {selectedLabel || resolvedPlaceholder}\n </span>\n <ChevronsUpDown className=\"size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[var(--radix-popover-trigger-width)] p-0\" align=\"start\">\n <Command shouldFilter={false}>\n <CommandInput\n placeholder={t('common:searchPlaceholder')}\n value={query}\n onValueChange={setQuery}\n />\n <CommandList>\n {search.isLoading && <div className=\"p-3 text-sm text-muted-foreground\">{t('common:loading')}</div>}\n {!search.isLoading && items.length === 0 && (\n <CommandEmpty>{t('common:noRecords')}</CommandEmpty>\n )}\n {value != null && value !== '' && (\n <CommandGroup>\n <CommandItem\n onSelect={() => {\n onChange(null)\n setOpen(false)\n }}\n >\n <Check className=\"size-4 opacity-0\" />\n <span className=\"text-muted-foreground\">{t('common:clearSelection')}</span>\n </CommandItem>\n </CommandGroup>\n )}\n <CommandGroup>\n {items.map((r) => {\n const isSelected = String(r.id) === String(value ?? '')\n return (\n <CommandItem\n key={r.id}\n value={r.id}\n onSelect={() => {\n onChange(r.id)\n setOpen(false)\n }}\n >\n <Check className={cn('size-4', isSelected ? 'opacity-100' : 'opacity-0')} />\n <span className=\"truncate\" title={r.title ? `${r.title} <${r.id}>` : `#${r.id}`}>\n {r.title ? `${r.title} <${r.id}>` : `#${r.id}`}\n </span>\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n\n/** Renders a list of comma-separated badge links, one per foreign key.\n *\n * When `populated` + `populatedKeyPrefix` are provided, each item is looked up\n * via `populated[`${prefix}.${id}`]` and threaded into its `<ReferenceLink>`\n * to suppress per-row `show` requests. The key shape matches what the m2m\n * feature's read-hook writes (see `packages/feature-m2m`) and what the list\n * action's `populateReferences` helper writes for array references. */\nexport function ReferenceLinkList({\n resourceId,\n recordIds,\n className,\n populated,\n populatedKeyPrefix,\n}: {\n resourceId: string\n recordIds: ReadonlyArray<string | number>\n className?: string\n populated?: Record<string, unknown>\n populatedKeyPrefix?: string\n}): React.ReactElement {\n if (!recordIds || recordIds.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n return (\n <div className={cn('flex flex-wrap gap-1', className)}>\n {recordIds.map((id) => {\n const entry =\n populated && populatedKeyPrefix\n ? (populated[`${populatedKeyPrefix}.${id}`] as\n | { id?: string; title?: string }\n | undefined)\n : undefined\n return (\n <ReferenceLink\n key={String(id)}\n resourceId={resourceId}\n recordId={id}\n populated={entry}\n />\n )\n })}\n </div>\n )\n}\n\n/** Multi-select combobox for many-to-many references. Renders selected items\n * as removable chips and feeds search results into a checkable command list. */\nexport function ReferenceMultiCombobox({\n referenceResourceId,\n value,\n onChange,\n disabled,\n placeholder,\n}: {\n referenceResourceId: string\n value: ReadonlyArray<string | number> | null | undefined\n onChange(next: Array<string | number>): void\n disabled?: boolean\n placeholder?: string\n}): React.ReactElement {\n const [open, setOpen] = React.useState(false)\n const [query, setQuery] = React.useState('')\n const debounced = useDebounced(query, 250)\n const client = useAdminClient()\n const { t } = useI18n()\n const resolvedPlaceholder = placeholder ?? t('common:select')\n const ids = React.useMemo(() => (value ?? []).map(String), [value])\n\n // Resolve labels per-id so adding/removing one item only fetches the new\n // one. Sharing the cache key with <ReferenceLink>'s single-record query\n // means already-known titles render instantly without flicker.\n const titleQueries = useQueries({\n queries: ids.map((id) => ({\n queryKey: ['modern-admin', referenceResourceId, 'show', id],\n queryFn: () => client.show(referenceResourceId, id),\n staleTime: 30_000,\n })),\n })\n const chips = React.useMemo(\n () =>\n ids.map((id, i) => {\n const t = titleQueries[i]?.data?.record?.title\n return { id, title: t ? `${t} <${id}>` : `#${id}` }\n }),\n [ids, titleQueries],\n )\n\n const search = useSearchRecords(referenceResourceId, debounced, open)\n const items = search.data?.records ?? []\n\n const toggle = (id: string | number): void => {\n const sid = String(id)\n const next = ids.includes(sid) ? ids.filter((x) => x !== sid) : [...ids, sid]\n onChange(next)\n }\n\n const remove = (id: string): void => {\n onChange(ids.filter((x) => x !== id))\n }\n\n return (\n <div className=\"space-y-2\">\n {chips.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {chips.map((s) => (\n <Badge key={s.id} variant=\"secondary\" className=\"gap-1 pr-1\">\n {s.title}\n <button\n type=\"button\"\n aria-label={t('common:removeItem', { title: s.title })}\n disabled={disabled}\n onClick={() => remove(s.id)}\n className=\"rounded-sm opacity-60 hover:opacity-100\"\n >\n <X className=\"size-3\" />\n </button>\n </Badge>\n ))}\n </div>\n )}\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled}\n className=\"w-full justify-between font-normal\"\n >\n <span className=\"truncate text-muted-foreground\">\n {ids.length > 0 ? t('common:nSelectedAddMore', { count: ids.length }) : resolvedPlaceholder}\n </span>\n <ChevronsUpDown className=\"size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[var(--radix-popover-trigger-width)] p-0\" align=\"start\">\n <Command shouldFilter={false}>\n <CommandInput placeholder={t('common:searchPlaceholder')} value={query} onValueChange={setQuery} />\n <CommandList>\n {search.isLoading && (\n <div className=\"p-3 text-sm text-muted-foreground\">{t('common:loading')}</div>\n )}\n {!search.isLoading && items.length === 0 && (\n <CommandEmpty>{t('common:noRecords')}</CommandEmpty>\n )}\n <CommandGroup>\n {items.map((r) => {\n const isSelected = ids.includes(String(r.id))\n return (\n <CommandItem\n key={r.id}\n value={String(r.id)}\n onSelect={() => toggle(r.id)}\n >\n <Check\n className={cn('size-4', isSelected ? 'opacity-100' : 'opacity-0')}\n />\n <span className=\"truncate\" title={r.title ? `${r.title} <${r.id}>` : `#${r.id}`}>\n {r.title ? `${r.title} <${r.id}>` : `#${r.id}`}\n </span>\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n )\n}\n\nconst useDebounced = <T,>(value: T, ms: number): T => {\n const [v, setV] = React.useState(value)\n React.useEffect(() => {\n const id = setTimeout(() => setV(value), ms)\n return () => clearTimeout(id)\n }, [value, ms])\n return v\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{t as e}from"./createLucideIcon-CUopU_LC.js";var t=e(`arrow-down`,[[`path`,{d:`M12 5v14`,key:`s699le`}],[`path`,{d:`m19 12-7 7-7-7`,key:`1idqje`}]]),n=e(`arrow-up`,[[`path`,{d:`m5 12 7-7 7 7`,key:`hav0vg`}],[`path`,{d:`M12 19V5`,key:`x0mq9r`}]]),r=e(`calendar`,[[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`4`,rx:`2`,key:`1hopcy`}],[`path`,{d:`M3 10h18`,key:`8toen8`}]]),i=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t as i,r as n,n as r,i as t};
|
|
2
|
+
//# sourceMappingURL=refresh-cw-DHvUQTMb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-cw-DHvUQTMb.js","names":["__iconNode","__iconNode","__iconNode"],"sources":["../../../../../node_modules/.bun/lucide-react@1.23.0+e14d3f224186685e/node_modules/lucide-react/dist/esm/icons/arrow-down.mjs","../../../../../node_modules/.bun/lucide-react@1.23.0+e14d3f224186685e/node_modules/lucide-react/dist/esm/icons/arrow-up.mjs","../../../../../node_modules/.bun/lucide-react@1.23.0+e14d3f224186685e/node_modules/lucide-react/dist/esm/icons/calendar.mjs","../../../../../node_modules/.bun/lucide-react@1.23.0+e14d3f224186685e/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs"],"sourcesContent":["/**\n * @license lucide-react v1.23.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }],\n [\"path\", { d: \"m19 12-7 7-7-7\", key: \"1idqje\" }]\n];\nconst ArrowDown = createLucideIcon(\"arrow-down\", __iconNode);\n\nexport { __iconNode, ArrowDown as default };\n//# sourceMappingURL=arrow-down.mjs.map\n","/**\n * @license lucide-react v1.23.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m5 12 7-7 7 7\", key: \"hav0vg\" }],\n [\"path\", { d: \"M12 19V5\", key: \"x0mq9r\" }]\n];\nconst ArrowUp = createLucideIcon(\"arrow-up\", __iconNode);\n\nexport { __iconNode, ArrowUp as default };\n//# sourceMappingURL=arrow-up.mjs.map\n","/**\n * @license lucide-react v1.23.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M8 2v4\", key: \"1cmpym\" }],\n [\"path\", { d: \"M16 2v4\", key: \"4m81vk\" }],\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"4\", rx: \"2\", key: \"1hopcy\" }],\n [\"path\", { d: \"M3 10h18\", key: \"8toen8\" }]\n];\nconst Calendar = createLucideIcon(\"calendar\", __iconNode);\n\nexport { __iconNode, Calendar as default };\n//# sourceMappingURL=calendar.mjs.map\n","/**\n * @license lucide-react v1.23.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\", key: \"v9h5vc\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }],\n [\"path\", { d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\", key: \"3uifl3\" }],\n [\"path\", { d: \"M8 16H3v5\", key: \"1cv678\" }]\n];\nconst RefreshCw = createLucideIcon(\"refresh-cw\", __iconNode);\n\nexport { __iconNode, RefreshCw as default };\n//# sourceMappingURL=refresh-cw.mjs.map\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"mDAaA,IAAM,EAAY,EAAiB,aAAcA,CAH/C,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,EACzC,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAS,CAAC,CAEAA,CAAU,ECArD,EAAU,EAAiB,WAAYC,CAH3C,CAAC,OAAQ,CAAE,EAAG,gBAAiB,IAAK,QAAS,CAAC,EAC9C,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,CAEEA,CAAU,ECEjD,EAAW,EAAiB,WAAYC,CAL5C,CAAC,OAAQ,CAAE,EAAG,SAAU,IAAK,QAAS,CAAC,EACvC,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAS,CAAC,EACxC,CAAC,OAAQ,CAAE,MAAO,KAAM,OAAQ,KAAM,EAAG,IAAK,EAAG,IAAK,GAAI,IAAK,IAAK,QAAS,CAAC,EAC9E,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAS,CAAC,CAEGA,CAAU,ECAlD,EAAY,EAAiB,aAAc,CAL/C,CAAC,OAAQ,CAAE,EAAG,qDAAsD,IAAK,QAAS,CAAC,EACnF,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAS,CAAC,EAC3C,CAAC,OAAQ,CAAE,EAAG,sDAAuD,IAAK,QAAS,CAAC,EACpF,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAS,CAAC,CAEK,CAAU"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,n as t}from"./createLucideIcon-CUopU_LC.js";import{S as n,s as r}from"./with-selector-NDLhu4dT.js";import{t as i}from"./rotate-ccw-BLr0QLAg.js";import{s as a}from"./dist-Dpg8xy_r.js";import{a as o,i as s,n as c,r as l,t as u}from"./select-BWf6walM.js";import{J as d,K as f,W as p,et as m}from"./router-wFvtgo77.js";import{a as h,i as g,n as _,r as v}from"./user-directory-9COoW6AO.js";import{H as y,d as b,f as x,i as S,l as C,p as w,r as T,s as E,ut as D}from"./index-t4woXGa-.js";var O=e(t(),1),k=n(),A={create:`Created`,update:`Updated`,delete:`Deleted`,unknownUser:`Unknown user`,changes:`changes`};function j({items:e,selectedId:t,labels:n,className:i,formatDate:a=e=>e,onSelect:o}){let s={...A,...n};return(0,k.jsx)(`div`,{className:r(`space-y-2`,i),children:e.map(e=>(0,k.jsxs)(`button`,{type:`button`,onClick:()=>o?.(e),className:r(`relative flex w-full gap-3 rounded-md border p-3 text-left transition-colors`,e.id===t?`border-primary bg-primary/5`:`border-border bg-card hover:bg-muted/50`),children:[(0,k.jsx)(`span`,{className:`mt-1 size-2.5 shrink-0 rounded-full bg-primary`}),(0,k.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,k.jsxs)(`span`,{className:`flex items-center justify-between gap-2`,children:[(0,k.jsx)(`span`,{className:`truncate text-sm font-medium`,children:M(e.op,s)}),e.changes!==void 0&&(0,k.jsxs)(`span`,{className:`shrink-0 text-xs text-muted-foreground`,children:[e.changes,` `,s.changes]})]}),(0,k.jsx)(`span`,{className:`block truncate text-xs text-muted-foreground`,children:e.userLabel??e.userId??s.unknownUser}),(0,k.jsx)(`span`,{className:`block text-xs text-muted-foreground`,children:a(e.createdAt)})]})]},e.id))})}function M(e,t){return e===`create`?t.create:e===`delete`?t.delete:t.update}function N({resourceId:e,recordId:t}){let{t:n,locale:r}=m(),A=f(e),M=p(e,t,{limit:50}),N=d(e,t),F=T(),I=S(),[L,R]=O.useState(!1),z=O.useMemo(()=>M.data?.revisions??[],[M.data?.revisions]),B=_(O.useMemo(()=>Array.from(new Set(z.map(e=>e.userId).filter(e=>!!e))),[z])),V=O.useCallback(e=>e?v(B.get(e),e):void 0,[B]),[H,U]=O.useState(),[W,G]=O.useState(``),K=z.find(e=>e.id===H)??z[0],q=W?z.find(e=>e.id===W):void 0,J=O.useMemo(()=>{let e={};for(let t of A?.properties??[])e[t.path]=t.label;return e},[A]),Y=O.useCallback(e=>e.map(e=>({...e,label:J[e.path]})),[J]),X=K?Y(q?g(q.snapshot,K.snapshot):P(K)):[];O.useEffect(()=>{!H&&z[0]&&U(z[0].id)},[z,H]),O.useEffect(()=>{K?.id&&W===K.id&&G(``)},[W,K?.id]);let Z=O.useCallback(e=>new Intl.DateTimeFormat(r,{dateStyle:`medium`,timeStyle:`short`}).format(new Date(e)),[r]),Q=async e=>{if(await F.confirm({title:n(`history:confirmRevert`),confirmLabel:n(`history:revert`),destructive:!0}))try{await N.mutateAsync({revisionId:e.id}),I.success({key:`history:revertSuccess`}),U(void 0),G(``),R(!1)}catch(e){I.error({key:`history:revertFailed`},{description:e instanceof Error?e.message:String(e)})}};return(0,k.jsxs)(E,{open:L,onOpenChange:R,children:[(0,k.jsx)(w,{asChild:!0,children:(0,k.jsxs)(a,{variant:`outline`,size:`sm`,"aria-label":n(`history:revisions`),children:[(0,k.jsx)(D,{className:`size-4`}),(0,k.jsx)(`span`,{className:`hidden sm:inline`,children:n(`history:revisions`)})]})}),(0,k.jsxs)(C,{side:`right`,className:`w-full overflow-y-auto sm:max-w-5xl`,children:[(0,k.jsx)(b,{children:(0,k.jsx)(x,{children:n(`history:revisions`)})}),M.isLoading?(0,k.jsxs)(`div`,{className:`mt-6 space-y-3`,children:[(0,k.jsx)(y,{className:`h-16 w-full`}),(0,k.jsx)(y,{className:`h-64 w-full`})]}):M.isError?(0,k.jsx)(`div`,{className:`mt-6 rounded-md border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive`,children:n(`history:loadError`)}):(0,k.jsxs)(`div`,{className:`mt-6 grid gap-4 lg:grid-cols-[20rem_1fr]`,children:[(0,k.jsx)(j,{items:z.map(e=>({id:e.id,op:e.op,userId:e.userId,userLabel:V(e.userId),createdAt:e.createdAt,changes:P(e).length})),selectedId:K?.id,onSelect:e=>U(e.id),formatDate:Z,labels:{create:n(`history:op.create`),update:n(`history:op.update`),delete:n(`history:op.delete`),unknownUser:n(`history:unknownUser`),changes:n(`history:changes`)}}),(0,k.jsx)(`div`,{className:`min-w-0 space-y-4`,children:K?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3 rounded-md border border-border bg-card p-3`,children:[(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`p`,{className:`text-sm font-medium`,children:Z(K.createdAt)}),(0,k.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:V(K.userId)??n(`history:unknownUser`)})]}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,k.jsxs)(u,{value:W||`_none_`,onValueChange:e=>G(e===`_none_`?``:e),children:[(0,k.jsx)(s,{className:`h-8 w-auto text-xs`,"aria-label":n(`history:compareTo`),children:(0,k.jsx)(o,{})}),(0,k.jsxs)(c,{children:[(0,k.jsx)(l,{value:`_none_`,children:n(`history:storedDiff`)}),z.filter(e=>e.id!==K.id).map(e=>(0,k.jsx)(l,{value:e.id,children:Z(e.createdAt)},e.id))]})]}),(0,k.jsxs)(a,{variant:`destructive`,size:`sm`,disabled:N.isPending||K.op===`delete`,onClick:()=>void Q(K),children:[(0,k.jsx)(i,{className:`size-4`}),n(`history:revert`)]})]})]}),(0,k.jsx)(h,{fields:X,labels:{added:n(`diff:added`),changed:n(`diff:changed`),removed:n(`diff:removed`),before:n(`diff:before`),after:n(`diff:after`),noChanges:n(`diff:noChanges`)}})]}):(0,k.jsx)(`div`,{className:`rounded-md border border-dashed p-8 text-center text-sm text-muted-foreground`,children:n(`history:noRevisions`)})})]})]})]})}var P=e=>g(e.snapshotBefore??{},e.snapshot);export{N as t};
|
|
2
|
+
//# sourceMappingURL=revisions-button-DXZAh2Lu.js.map
|
|
Binary file
|
|
Binary file
|
package/dist/standalone/assets/{revisions-button-hLRZGkwM.js.map → revisions-button-DXZAh2Lu.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revisions-button-hLRZGkwM.js","names":[],"sources":["../../../../ui/src/components/revision-timeline.tsx","../../../../react/src/components/revisions-button.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../lib/utils.js'\n\nexport interface RevisionTimelineItem {\n id: string\n op: 'create' | 'update' | 'delete'\n userId?: string\n /** Resolved, human-readable label for the user who created the revision\n * (e.g. email or full name). When set, it's shown instead of the raw\n * `userId`. Resolution happens in the React layer so this UI component\n * stays i18n- and data-source-agnostic. */\n userLabel?: string\n createdAt: string\n changes?: number\n}\n\nexport interface RevisionTimelineLabels {\n create?: string\n update?: string\n delete?: string\n unknownUser?: string\n changes?: string\n}\n\nexport interface RevisionTimelineProps {\n items: ReadonlyArray<RevisionTimelineItem>\n selectedId?: string\n labels?: RevisionTimelineLabels\n className?: string\n formatDate?: (value: string) => string\n onSelect?: (item: RevisionTimelineItem) => void\n}\n\nconst DEFAULT_LABELS: Required<RevisionTimelineLabels> = {\n create: 'Created',\n update: 'Updated',\n delete: 'Deleted',\n unknownUser: 'Unknown user',\n changes: 'changes',\n}\n\nexport function RevisionTimeline({\n items,\n selectedId,\n labels,\n className,\n formatDate = (v) => v,\n onSelect,\n}: RevisionTimelineProps): React.ReactElement {\n const l = { ...DEFAULT_LABELS, ...labels }\n return (\n <div className={cn('space-y-2', className)}>\n {items.map((item) => {\n const selected = item.id === selectedId\n return (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => onSelect?.(item)}\n className={cn(\n 'relative flex w-full gap-3 rounded-md border p-3 text-left transition-colors',\n selected ? 'border-primary bg-primary/5' : 'border-border bg-card hover:bg-muted/50',\n )}\n >\n <span className=\"mt-1 size-2.5 shrink-0 rounded-full bg-primary\" />\n <span className=\"min-w-0 flex-1 space-y-1\">\n <span className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate text-sm font-medium\">{labelForOp(item.op, l)}</span>\n {item.changes !== undefined && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">\n {item.changes} {l.changes}\n </span>\n )}\n </span>\n <span className=\"block truncate text-xs text-muted-foreground\">\n {item.userLabel ?? item.userId ?? l.unknownUser}\n </span>\n <span className=\"block text-xs text-muted-foreground\">\n {formatDate(item.createdAt)}\n </span>\n </span>\n </button>\n )\n })}\n </div>\n )\n}\n\nfunction labelForOp(op: RevisionTimelineItem['op'], labels: Required<RevisionTimelineLabels>): string {\n if (op === 'create') return labels.create\n if (op === 'delete') return labels.delete\n return labels.update\n}\n","import * as React from 'react'\nimport {\n Button,\n DiffView,\n RevisionTimeline,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n Skeleton,\n} from '@modern-admin/ui'\nimport { History, RotateCcw } from 'lucide-react'\nimport { diffSnapshots } from '@modern-admin/core'\nimport { useRecordHistory, useResource, useRevertRevision } from '../hooks.js'\nimport { useI18n } from '../i18n.js'\nimport { useDialogs } from '../dialogs.js'\nimport { useNotify } from '../notify.js'\nimport { useUserDirectory, userLabelOf } from '../user-directory.js'\nimport type { HistoryDiffEntry, HistoryRevision } from '../client.js'\n\nexport interface RevisionsButtonProps {\n resourceId: string\n recordId: string\n}\n\nexport function RevisionsButton({\n resourceId,\n recordId,\n}: RevisionsButtonProps): React.ReactElement {\n const { t, locale } = useI18n()\n const resource = useResource(resourceId)\n const history = useRecordHistory(resourceId, recordId, { limit: 50 })\n const revert = useRevertRevision(resourceId, recordId)\n const dialogs = useDialogs()\n const notify = useNotify()\n const [open, setOpen] = React.useState(false)\n const revisions = React.useMemo(\n () => history.data?.revisions ?? [],\n [history.data?.revisions],\n )\n // Resolve revision authors to human-readable labels (email / name)\n // instead of showing raw user UUIDs.\n const userIds = React.useMemo(\n () => Array.from(new Set(revisions.map((r) => r.userId).filter((v): v is string => !!v))),\n [revisions],\n )\n const users = useUserDirectory(userIds)\n const labelForUser = React.useCallback(\n (userId: string | undefined): string | undefined =>\n userId ? userLabelOf(users.get(userId), userId) : undefined,\n [users],\n )\n const [selectedId, setSelectedId] = React.useState<string | undefined>()\n const [compareToId, setCompareToId] = React.useState<string>('')\n const selected = revisions.find((r) => r.id === selectedId) ?? revisions[0]\n const compareTo = compareToId\n ? revisions.find((r) => r.id === compareToId)\n : undefined\n\n // Build a path → label map from the resource schema so each diff field\n // can show a human-readable name before its technical path.\n const labelByPath = React.useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {}\n for (const p of resource?.properties ?? []) map[p.path] = p.label\n return map\n }, [resource])\n\n const withLabels = React.useCallback(\n (fields: ReturnType<typeof diffSnapshots>) =>\n fields.map((f) => ({ ...f, label: labelByPath[f.path] })),\n [labelByPath],\n )\n\n const visibleFields = selected\n ? withLabels(\n compareTo\n ? diffSnapshots(compareTo.snapshot, selected.snapshot)\n : fieldsFor(selected),\n )\n : []\n\n React.useEffect(() => {\n if (!selectedId && revisions[0]) setSelectedId(revisions[0].id)\n }, [revisions, selectedId])\n\n React.useEffect(() => {\n if (selected?.id && compareToId === selected.id) setCompareToId('')\n }, [compareToId, selected?.id])\n\n const formatDate = React.useCallback(\n (value: string) => new Intl.DateTimeFormat(locale, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(new Date(value)),\n [locale],\n )\n\n const handleRevert = async (revision: HistoryRevision): Promise<void> => {\n const ok = await dialogs.confirm({\n title: t('history:confirmRevert'),\n confirmLabel: t('history:revert'),\n destructive: true,\n })\n if (!ok) return\n try {\n await revert.mutateAsync({ revisionId: revision.id })\n notify.success({ key: 'history:revertSuccess' })\n setSelectedId(undefined)\n setCompareToId('')\n setOpen(false)\n } catch (err) {\n notify.error(\n { key: 'history:revertFailed' },\n { description: err instanceof Error ? err.message : String(err) },\n )\n }\n }\n\n return (\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" aria-label={t('history:revisions')}>\n <History className=\"size-4\" />\n <span className=\"hidden sm:inline\">{t('history:revisions')}</span>\n </Button>\n </SheetTrigger>\n <SheetContent side=\"right\" className=\"w-full overflow-y-auto sm:max-w-5xl\">\n <SheetHeader>\n <SheetTitle>{t('history:revisions')}</SheetTitle>\n </SheetHeader>\n {history.isLoading ? (\n <div className=\"mt-6 space-y-3\">\n <Skeleton className=\"h-16 w-full\" />\n <Skeleton className=\"h-64 w-full\" />\n </div>\n ) : history.isError ? (\n <div className=\"mt-6 rounded-md border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive\">\n {t('history:loadError')}\n </div>\n ) : (\n <div className=\"mt-6 grid gap-4 lg:grid-cols-[20rem_1fr]\">\n <RevisionTimeline\n items={revisions.map((r) => ({\n id: r.id,\n op: r.op,\n userId: r.userId,\n userLabel: labelForUser(r.userId),\n createdAt: r.createdAt,\n changes: fieldsFor(r).length,\n }))}\n selectedId={selected?.id}\n onSelect={(item) => setSelectedId(item.id)}\n formatDate={formatDate}\n labels={{\n create: t('history:op.create'),\n update: t('history:op.update'),\n delete: t('history:op.delete'),\n unknownUser: t('history:unknownUser'),\n changes: t('history:changes'),\n }}\n />\n <div className=\"min-w-0 space-y-4\">\n {selected ? (\n <>\n <div className=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-border bg-card p-3\">\n <div>\n <p className=\"text-sm font-medium\">{formatDate(selected.createdAt)}</p>\n <p className=\"text-xs text-muted-foreground\">\n {labelForUser(selected.userId) ?? t('history:unknownUser')}\n </p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Select\n value={compareToId || '_none_'}\n onValueChange={(v) => setCompareToId(v === '_none_' ? '' : v)}\n >\n <SelectTrigger\n className=\"h-8 w-auto text-xs\"\n aria-label={t('history:compareTo')}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"_none_\">{t('history:storedDiff')}</SelectItem>\n {revisions\n .filter((r) => r.id !== selected.id)\n .map((revision) => (\n <SelectItem key={revision.id} value={revision.id}>\n {formatDate(revision.createdAt)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n disabled={revert.isPending || selected.op === 'delete'}\n onClick={() => void handleRevert(selected)}\n >\n <RotateCcw className=\"size-4\" />\n {t('history:revert')}\n </Button>\n </div>\n </div>\n <DiffView\n fields={visibleFields}\n labels={{\n added: t('diff:added'),\n changed: t('diff:changed'),\n removed: t('diff:removed'),\n before: t('diff:before'),\n after: t('diff:after'),\n noChanges: t('diff:noChanges'),\n }}\n />\n </>\n ) : (\n <div className=\"rounded-md border border-dashed p-8 text-center text-sm text-muted-foreground\">\n {t('history:noRevisions')}\n </div>\n )}\n </div>\n </div>\n )}\n </SheetContent>\n </Sheet>\n )\n}\n\nconst fieldsFor = (revision: HistoryRevision): HistoryDiffEntry[] =>\n diffSnapshots(revision.snapshotBefore ?? {}, revision.snapshot)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"revisions-button-DXZAh2Lu.js","names":[],"sources":["../../../../ui/src/components/revision-timeline.tsx","../../../../react/src/components/revisions-button.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../lib/utils.js'\n\nexport interface RevisionTimelineItem {\n id: string\n op: 'create' | 'update' | 'delete'\n userId?: string\n /** Resolved, human-readable label for the user who created the revision\n * (e.g. email or full name). When set, it's shown instead of the raw\n * `userId`. Resolution happens in the React layer so this UI component\n * stays i18n- and data-source-agnostic. */\n userLabel?: string\n createdAt: string\n changes?: number\n}\n\nexport interface RevisionTimelineLabels {\n create?: string\n update?: string\n delete?: string\n unknownUser?: string\n changes?: string\n}\n\nexport interface RevisionTimelineProps {\n items: ReadonlyArray<RevisionTimelineItem>\n selectedId?: string\n labels?: RevisionTimelineLabels\n className?: string\n formatDate?: (value: string) => string\n onSelect?: (item: RevisionTimelineItem) => void\n}\n\nconst DEFAULT_LABELS: Required<RevisionTimelineLabels> = {\n create: 'Created',\n update: 'Updated',\n delete: 'Deleted',\n unknownUser: 'Unknown user',\n changes: 'changes',\n}\n\nexport function RevisionTimeline({\n items,\n selectedId,\n labels,\n className,\n formatDate = (v) => v,\n onSelect,\n}: RevisionTimelineProps): React.ReactElement {\n const l = { ...DEFAULT_LABELS, ...labels }\n return (\n <div className={cn('space-y-2', className)}>\n {items.map((item) => {\n const selected = item.id === selectedId\n return (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => onSelect?.(item)}\n className={cn(\n 'relative flex w-full gap-3 rounded-md border p-3 text-left transition-colors',\n selected ? 'border-primary bg-primary/5' : 'border-border bg-card hover:bg-muted/50',\n )}\n >\n <span className=\"mt-1 size-2.5 shrink-0 rounded-full bg-primary\" />\n <span className=\"min-w-0 flex-1 space-y-1\">\n <span className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate text-sm font-medium\">{labelForOp(item.op, l)}</span>\n {item.changes !== undefined && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">\n {item.changes} {l.changes}\n </span>\n )}\n </span>\n <span className=\"block truncate text-xs text-muted-foreground\">\n {item.userLabel ?? item.userId ?? l.unknownUser}\n </span>\n <span className=\"block text-xs text-muted-foreground\">\n {formatDate(item.createdAt)}\n </span>\n </span>\n </button>\n )\n })}\n </div>\n )\n}\n\nfunction labelForOp(op: RevisionTimelineItem['op'], labels: Required<RevisionTimelineLabels>): string {\n if (op === 'create') return labels.create\n if (op === 'delete') return labels.delete\n return labels.update\n}\n","import * as React from 'react'\nimport {\n Button,\n DiffView,\n RevisionTimeline,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n Skeleton,\n} from '@modern-admin/ui'\nimport { History, RotateCcw } from 'lucide-react'\nimport { diffSnapshots } from '@modern-admin/core'\nimport { useRecordHistory, useResource, useRevertRevision } from '../hooks.js'\nimport { useI18n } from '../i18n.js'\nimport { useDialogs } from '../dialogs.js'\nimport { useNotify } from '../notify.js'\nimport { useUserDirectory, userLabelOf } from '../user-directory.js'\nimport type { HistoryDiffEntry, HistoryRevision } from '../client.js'\n\nexport interface RevisionsButtonProps {\n resourceId: string\n recordId: string\n}\n\nexport function RevisionsButton({\n resourceId,\n recordId,\n}: RevisionsButtonProps): React.ReactElement {\n const { t, locale } = useI18n()\n const resource = useResource(resourceId)\n const history = useRecordHistory(resourceId, recordId, { limit: 50 })\n const revert = useRevertRevision(resourceId, recordId)\n const dialogs = useDialogs()\n const notify = useNotify()\n const [open, setOpen] = React.useState(false)\n const revisions = React.useMemo(\n () => history.data?.revisions ?? [],\n [history.data?.revisions],\n )\n // Resolve revision authors to human-readable labels (email / name)\n // instead of showing raw user UUIDs.\n const userIds = React.useMemo(\n () => Array.from(new Set(revisions.map((r) => r.userId).filter((v): v is string => !!v))),\n [revisions],\n )\n const users = useUserDirectory(userIds)\n const labelForUser = React.useCallback(\n (userId: string | undefined): string | undefined =>\n userId ? userLabelOf(users.get(userId), userId) : undefined,\n [users],\n )\n const [selectedId, setSelectedId] = React.useState<string | undefined>()\n const [compareToId, setCompareToId] = React.useState<string>('')\n const selected = revisions.find((r) => r.id === selectedId) ?? revisions[0]\n const compareTo = compareToId\n ? revisions.find((r) => r.id === compareToId)\n : undefined\n\n // Build a path → label map from the resource schema so each diff field\n // can show a human-readable name before its technical path.\n const labelByPath = React.useMemo<Record<string, string>>(() => {\n const map: Record<string, string> = {}\n for (const p of resource?.properties ?? []) map[p.path] = p.label\n return map\n }, [resource])\n\n const withLabels = React.useCallback(\n (fields: ReturnType<typeof diffSnapshots>) =>\n fields.map((f) => ({ ...f, label: labelByPath[f.path] })),\n [labelByPath],\n )\n\n const visibleFields = selected\n ? withLabels(\n compareTo\n ? diffSnapshots(compareTo.snapshot, selected.snapshot)\n : fieldsFor(selected),\n )\n : []\n\n React.useEffect(() => {\n if (!selectedId && revisions[0]) setSelectedId(revisions[0].id)\n }, [revisions, selectedId])\n\n React.useEffect(() => {\n if (selected?.id && compareToId === selected.id) setCompareToId('')\n }, [compareToId, selected?.id])\n\n const formatDate = React.useCallback(\n (value: string) => new Intl.DateTimeFormat(locale, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(new Date(value)),\n [locale],\n )\n\n const handleRevert = async (revision: HistoryRevision): Promise<void> => {\n const ok = await dialogs.confirm({\n title: t('history:confirmRevert'),\n confirmLabel: t('history:revert'),\n destructive: true,\n })\n if (!ok) return\n try {\n await revert.mutateAsync({ revisionId: revision.id })\n notify.success({ key: 'history:revertSuccess' })\n setSelectedId(undefined)\n setCompareToId('')\n setOpen(false)\n } catch (err) {\n notify.error(\n { key: 'history:revertFailed' },\n { description: err instanceof Error ? err.message : String(err) },\n )\n }\n }\n\n return (\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" aria-label={t('history:revisions')}>\n <History className=\"size-4\" />\n <span className=\"hidden sm:inline\">{t('history:revisions')}</span>\n </Button>\n </SheetTrigger>\n <SheetContent side=\"right\" className=\"w-full overflow-y-auto sm:max-w-5xl\">\n <SheetHeader>\n <SheetTitle>{t('history:revisions')}</SheetTitle>\n </SheetHeader>\n {history.isLoading ? (\n <div className=\"mt-6 space-y-3\">\n <Skeleton className=\"h-16 w-full\" />\n <Skeleton className=\"h-64 w-full\" />\n </div>\n ) : history.isError ? (\n <div className=\"mt-6 rounded-md border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive\">\n {t('history:loadError')}\n </div>\n ) : (\n <div className=\"mt-6 grid gap-4 lg:grid-cols-[20rem_1fr]\">\n <RevisionTimeline\n items={revisions.map((r) => ({\n id: r.id,\n op: r.op,\n userId: r.userId,\n userLabel: labelForUser(r.userId),\n createdAt: r.createdAt,\n changes: fieldsFor(r).length,\n }))}\n selectedId={selected?.id}\n onSelect={(item) => setSelectedId(item.id)}\n formatDate={formatDate}\n labels={{\n create: t('history:op.create'),\n update: t('history:op.update'),\n delete: t('history:op.delete'),\n unknownUser: t('history:unknownUser'),\n changes: t('history:changes'),\n }}\n />\n <div className=\"min-w-0 space-y-4\">\n {selected ? (\n <>\n <div className=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-border bg-card p-3\">\n <div>\n <p className=\"text-sm font-medium\">{formatDate(selected.createdAt)}</p>\n <p className=\"text-xs text-muted-foreground\">\n {labelForUser(selected.userId) ?? t('history:unknownUser')}\n </p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Select\n value={compareToId || '_none_'}\n onValueChange={(v) => setCompareToId(v === '_none_' ? '' : v)}\n >\n <SelectTrigger\n className=\"h-8 w-auto text-xs\"\n aria-label={t('history:compareTo')}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"_none_\">{t('history:storedDiff')}</SelectItem>\n {revisions\n .filter((r) => r.id !== selected.id)\n .map((revision) => (\n <SelectItem key={revision.id} value={revision.id}>\n {formatDate(revision.createdAt)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n disabled={revert.isPending || selected.op === 'delete'}\n onClick={() => void handleRevert(selected)}\n >\n <RotateCcw className=\"size-4\" />\n {t('history:revert')}\n </Button>\n </div>\n </div>\n <DiffView\n fields={visibleFields}\n labels={{\n added: t('diff:added'),\n changed: t('diff:changed'),\n removed: t('diff:removed'),\n before: t('diff:before'),\n after: t('diff:after'),\n noChanges: t('diff:noChanges'),\n }}\n />\n </>\n ) : (\n <div className=\"rounded-md border border-dashed p-8 text-center text-sm text-muted-foreground\">\n {t('history:noRevisions')}\n </div>\n )}\n </div>\n </div>\n )}\n </SheetContent>\n </Sheet>\n )\n}\n\nconst fieldsFor = (revision: HistoryRevision): HistoryDiffEntry[] =>\n diffSnapshots(revision.snapshotBefore ?? {}, revision.snapshot)\n"],"mappings":"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"}
|