mongoku 2.4.6 → 2.4.7-compat
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 +15 -0
- package/build/client/_app/immutable/assets/0.C_geP4pp.css +1 -0
- package/build/client/_app/immutable/assets/0.C_geP4pp.css.br +0 -0
- package/build/client/_app/immutable/assets/0.C_geP4pp.css.gz +0 -0
- package/build/client/_app/immutable/assets/10.Wc4MTSzM.css +1 -0
- package/build/client/_app/immutable/assets/10.Wc4MTSzM.css.br +0 -0
- package/build/client/_app/immutable/assets/10.Wc4MTSzM.css.gz +0 -0
- package/build/client/_app/immutable/assets/{Modal.zD4dMMyk.css → Modal.CZgFKXkP.css} +1 -1
- package/build/client/_app/immutable/assets/Modal.CZgFKXkP.css.br +0 -0
- package/build/client/_app/immutable/assets/Modal.CZgFKXkP.css.gz +0 -0
- package/build/client/_app/immutable/chunks/B27BoO92.js +1 -0
- package/build/client/_app/immutable/chunks/B27BoO92.js.br +0 -0
- package/build/client/_app/immutable/chunks/B27BoO92.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{reNJcONQ.js → BLB7WU0x.js} +1 -1
- package/build/client/_app/immutable/chunks/BLB7WU0x.js.br +0 -0
- package/build/client/_app/immutable/chunks/{reNJcONQ.js.gz → BLB7WU0x.js.gz} +0 -0
- package/build/client/_app/immutable/chunks/{Dkr5ZtQR.js → BTDPx7wo.js} +1 -1
- package/build/client/_app/immutable/chunks/BTDPx7wo.js.br +0 -0
- package/build/client/_app/immutable/chunks/BTDPx7wo.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BziC6PX1.js → BV1jCwWf.js} +1 -1
- package/build/client/_app/immutable/chunks/BV1jCwWf.js.br +0 -0
- package/build/client/_app/immutable/chunks/BV1jCwWf.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bp2iD_PL.js +1 -0
- package/build/client/_app/immutable/chunks/Bp2iD_PL.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bp2iD_PL.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CItzKczS.js +1 -0
- package/build/client/_app/immutable/chunks/CItzKczS.js.br +0 -0
- package/build/client/_app/immutable/chunks/CItzKczS.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BO6_ugNx.js → Ce084HhL.js} +1 -1
- package/build/client/_app/immutable/chunks/Ce084HhL.js.br +0 -0
- package/build/client/_app/immutable/chunks/Ce084HhL.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DIw4Wyr4.js → CqFYS5AV.js} +1 -1
- package/build/client/_app/immutable/chunks/CqFYS5AV.js.br +0 -0
- package/build/client/_app/immutable/chunks/CqFYS5AV.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CpnIKQd1.js → DC13l09X.js} +6 -6
- package/build/client/_app/immutable/chunks/DC13l09X.js.br +0 -0
- package/build/client/_app/immutable/chunks/DC13l09X.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DkI4PMxL.js → DXWJTsg6.js} +1 -1
- package/build/client/_app/immutable/chunks/DXWJTsg6.js.br +0 -0
- package/build/client/_app/immutable/chunks/DXWJTsg6.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dip-8jE5.js +1 -0
- package/build/client/_app/immutable/chunks/Dip-8jE5.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dip-8jE5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dr_XE7iR.js +2 -0
- package/build/client/_app/immutable/chunks/Dr_XE7iR.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dr_XE7iR.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DuLpG1zT.js +1 -0
- package/build/client/_app/immutable/chunks/DuLpG1zT.js.br +0 -0
- package/build/client/_app/immutable/chunks/DuLpG1zT.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{Dn0_-jEe.js → DyfVYlRP.js} +1 -1
- package/build/client/_app/immutable/chunks/DyfVYlRP.js.br +0 -0
- package/build/client/_app/immutable/chunks/DyfVYlRP.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BXUq66wC.js → OTbFjzBQ.js} +1 -1
- package/build/client/_app/immutable/chunks/OTbFjzBQ.js.br +0 -0
- package/build/client/_app/immutable/chunks/OTbFjzBQ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{UJuWD2W4.js → TQ9V_LBO.js} +1 -1
- package/build/client/_app/immutable/chunks/TQ9V_LBO.js.br +0 -0
- package/build/client/_app/immutable/chunks/TQ9V_LBO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{Z2a-si5C.js → p4lxgeXU.js} +3 -3
- package/build/client/_app/immutable/chunks/p4lxgeXU.js.br +0 -0
- package/build/client/_app/immutable/chunks/p4lxgeXU.js.gz +0 -0
- package/build/client/_app/immutable/chunks/pXcSrKpr.js +1 -0
- package/build/client/_app/immutable/chunks/pXcSrKpr.js.br +0 -0
- package/build/client/_app/immutable/chunks/pXcSrKpr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/xuMwtvm-.js +16 -0
- package/build/client/_app/immutable/chunks/xuMwtvm-.js.br +0 -0
- package/build/client/_app/immutable/chunks/xuMwtvm-.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.B7JBkmJ2.js +2 -0
- package/build/client/_app/immutable/entry/app.B7JBkmJ2.js.br +0 -0
- package/build/client/_app/immutable/entry/app.B7JBkmJ2.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.C35Eiz23.js +1 -0
- package/build/client/_app/immutable/entry/start.C35Eiz23.js.br +2 -0
- package/build/client/_app/immutable/entry/start.C35Eiz23.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.U3Wc2t11.js +1 -0
- package/build/client/_app/immutable/nodes/0.U3Wc2t11.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.U3Wc2t11.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.YN6Ljj2X.js +1 -0
- package/build/client/_app/immutable/nodes/1.YN6Ljj2X.js.br +2 -0
- package/build/client/_app/immutable/nodes/1.YN6Ljj2X.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.E5c2rVVT.js +3 -0
- package/build/client/_app/immutable/nodes/10.E5c2rVVT.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.E5c2rVVT.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{11.IKyzjYy6.js → 11.CwiIDBVl.js} +1 -1
- package/build/client/_app/immutable/nodes/11.CwiIDBVl.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.CwiIDBVl.js.gz +0 -0
- package/build/client/_app/immutable/nodes/12.BF4KBraU.js +1 -0
- package/build/client/_app/immutable/nodes/12.BF4KBraU.js.br +0 -0
- package/build/client/_app/immutable/nodes/12.BF4KBraU.js.gz +0 -0
- package/build/client/_app/immutable/nodes/13.BNgciqug.js +65 -0
- package/build/client/_app/immutable/nodes/13.BNgciqug.js.br +0 -0
- package/build/client/_app/immutable/nodes/13.BNgciqug.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{2.DqvBb3C7.js → 2.Byf6opOr.js} +1 -1
- package/build/client/_app/immutable/nodes/2.Byf6opOr.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.Byf6opOr.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{3.27swwcG4.js → 3.B3j0bAgy.js} +1 -1
- package/build/client/_app/immutable/nodes/3.B3j0bAgy.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.B3j0bAgy.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{4.CcholrFe.js → 4.6dtz57ii.js} +1 -1
- package/build/client/_app/immutable/nodes/4.6dtz57ii.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.6dtz57ii.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{5.CzudN9q-.js → 5.COHVaEDo.js} +1 -1
- package/build/client/_app/immutable/nodes/5.COHVaEDo.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.COHVaEDo.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{7.C560Uxhw.js → 7.Cecp1nCH.js} +1 -1
- package/build/client/_app/immutable/nodes/7.Cecp1nCH.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.Cecp1nCH.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{8.BEOgol-D.js → 8.DFk2Y9sL.js} +1 -1
- package/build/client/_app/immutable/nodes/8.DFk2Y9sL.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.DFk2Y9sL.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{9.BmG9LqpS.js → 9.W4l2xsEF.js} +1 -1
- package/build/client/_app/immutable/nodes/9.W4l2xsEF.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.W4l2xsEF.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/0-CuiS31Ys.js +22 -0
- package/build/server/chunks/{0-DgHP79Ti.js.map → 0-CuiS31Ys.js.map} +1 -1
- package/build/server/chunks/1-C9TxPuQ0.js +9 -0
- package/build/server/chunks/{1--T1OTbjT.js.map → 1-C9TxPuQ0.js.map} +1 -1
- package/build/server/chunks/{10-D1OhJt-m.js → 10-PX9d-jhv.js} +5 -5
- package/build/server/chunks/10-PX9d-jhv.js.map +1 -0
- package/build/server/chunks/{11-pr9S-VkT.js → 11-Bhv-UeEo.js} +4 -4
- package/build/server/chunks/{11-pr9S-VkT.js.map → 11-Bhv-UeEo.js.map} +1 -1
- package/build/server/chunks/{12-B_w9udgo.js → 12-BuNmW-Vp.js} +5 -5
- package/build/server/chunks/{12-B_w9udgo.js.map → 12-BuNmW-Vp.js.map} +1 -1
- package/build/server/chunks/{13-CfrLQ4p0.js → 13-CAI7Pyhf.js} +4 -4
- package/build/server/chunks/{13-CfrLQ4p0.js.map → 13-CAI7Pyhf.js.map} +1 -1
- package/build/server/chunks/{2-BheEgghx.js → 2-Bx656tbc.js} +2 -2
- package/build/server/chunks/{2-BheEgghx.js.map → 2-Bx656tbc.js.map} +1 -1
- package/build/server/chunks/{3-BwrTscBH.js → 3-B-zRiOJV.js} +2 -2
- package/build/server/chunks/{3-BwrTscBH.js.map → 3-B-zRiOJV.js.map} +1 -1
- package/build/server/chunks/{4-D28kbpdN.js → 4-BBCE4OIo.js} +2 -2
- package/build/server/chunks/{4-D28kbpdN.js.map → 4-BBCE4OIo.js.map} +1 -1
- package/build/server/chunks/{5--wY8V1OC.js → 5-D68X5smv.js} +2 -2
- package/build/server/chunks/{5--wY8V1OC.js.map → 5-D68X5smv.js.map} +1 -1
- package/build/server/chunks/{7-9IXFVUUl.js → 7-C8AZjmDc.js} +4 -4
- package/build/server/chunks/{7-9IXFVUUl.js.map → 7-C8AZjmDc.js.map} +1 -1
- package/build/server/chunks/{8-DQQl8f10.js → 8-CGRiuqYX.js} +5 -5
- package/build/server/chunks/{8-DQQl8f10.js.map → 8-CGRiuqYX.js.map} +1 -1
- package/build/server/chunks/{9-B4xWo186.js → 9-CBzIf4Vj.js} +5 -5
- package/build/server/chunks/{9-B4xWo186.js.map → 9-CBzIf4Vj.js.map} +1 -1
- package/build/server/chunks/{JsonValue-Cexm3jGT.js → JsonValue-EppVzWzE.js} +88 -36
- package/build/server/chunks/JsonValue-EppVzWzE.js.map +1 -0
- package/build/server/chunks/{Modal-BzZ9u6V6.js → Modal-eRpc5lqR.js} +4 -3
- package/build/server/chunks/Modal-eRpc5lqR.js.map +1 -0
- package/build/server/chunks/{Panel-BHGtM9Vw.js → Panel-HO9t9Spv.js} +2 -2
- package/build/server/chunks/{Panel-BHGtM9Vw.js.map → Panel-HO9t9Spv.js.map} +1 -1
- package/build/server/chunks/{PrettyJson-tOt0PqjF.js → PrettyJson-F3fqxkqU.js} +7 -6
- package/build/server/chunks/PrettyJson-F3fqxkqU.js.map +1 -0
- package/build/server/chunks/{Tooltip-DAE2mkm6.js → Tooltip-Dd-Bzogp.js} +2 -2
- package/build/server/chunks/{Tooltip-DAE2mkm6.js.map → Tooltip-Dd-Bzogp.js.map} +1 -1
- package/build/server/chunks/{TooltipTable-xo_OEG9c.js → TooltipTable-jHWezlEs.js} +3 -3
- package/build/server/chunks/{TooltipTable-xo_OEG9c.js.map → TooltipTable-jHWezlEs.js.map} +1 -1
- package/build/server/chunks/{_layout.svelte-Dji2JJ9X.js → _layout.svelte-CKGgUBvr.js} +9 -3
- package/build/server/chunks/_layout.svelte-CKGgUBvr.js.map +1 -0
- package/build/server/chunks/_page.svelte-BlmdSnTh.js +245 -0
- package/build/server/chunks/_page.svelte-BlmdSnTh.js.map +1 -0
- package/build/server/chunks/{_page.svelte-x1L5xjgQ.js → _page.svelte-ClZj6yzK.js} +7 -7
- package/build/server/chunks/{_page.svelte-x1L5xjgQ.js.map → _page.svelte-ClZj6yzK.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-be8sxgGt.js → _page.svelte-D50SWEhd.js} +8 -8
- package/build/server/chunks/{_page.svelte-be8sxgGt.js.map → _page.svelte-D50SWEhd.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-D-23v2Aa.js → _page.svelte-D8GSKYqN.js} +223 -12
- package/build/server/chunks/_page.svelte-D8GSKYqN.js.map +1 -0
- package/build/server/chunks/{_page.svelte-D9IvgJO5.js → _page.svelte-DBcsXxML.js} +8 -8
- package/build/server/chunks/{_page.svelte-D9IvgJO5.js.map → _page.svelte-DBcsXxML.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-aT9hOnbL.js → _page.svelte-DFzKfImt.js} +8 -8
- package/build/server/chunks/{_page.svelte-aT9hOnbL.js.map → _page.svelte-DFzKfImt.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-D5-pMskg.js → _page.svelte-ZYW4iSHn.js} +8 -8
- package/build/server/chunks/{_page.svelte-D5-pMskg.js.map → _page.svelte-ZYW4iSHn.js.map} +1 -1
- package/build/server/chunks/{index2-eSFyMQpS.js → index2-DBFlGzWV.js} +2 -2
- package/build/server/chunks/{index2-eSFyMQpS.js.map → index2-DBFlGzWV.js.map} +1 -1
- package/build/server/chunks/{mongo-BHk5yAj9.js → mongo-Ndoh6fs5.js} +21 -7
- package/build/server/chunks/mongo-Ndoh6fs5.js.map +1 -0
- package/build/server/chunks/{remote-xxtqbu-ETLGkdRu.js → remote-xxtqbu-fbBqzvFu.js} +3 -3
- package/build/server/chunks/remote-xxtqbu-fbBqzvFu.js.map +1 -0
- package/build/server/chunks/{servers.remote-CGies_Na.js → servers.remote-B1eorl4A.js} +163 -12
- package/build/server/chunks/servers.remote-B1eorl4A.js.map +1 -0
- package/build/server/index.js +2 -2
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +15 -15
- package/build/server/manifest.js.map +1 -1
- package/package.json +1 -1
- package/src/api/servers.remote.ts +196 -10
- package/src/app.css +3 -6
- package/src/lib/components/ExplainPanel.svelte +273 -0
- package/src/lib/components/JsonValue.svelte +51 -6
- package/src/lib/components/Modal.svelte +7 -2
- package/src/lib/components/Notifications.svelte +3 -15
- package/src/lib/components/PrettyJson.svelte +1 -1
- package/src/lib/components/SearchBox.svelte +160 -5
- package/src/lib/components/TimeRangeStats.svelte +269 -0
- package/src/lib/icons/IconClose.svelte +21 -0
- package/src/lib/icons/IconExternalLink.svelte +22 -0
- package/src/lib/server/mongo.ts +31 -6
- package/src/lib/types.ts +16 -5
- package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/+page.svelte +49 -1
- package/src/routes/servers/[server]/databases/[database]/collections/[collection]/mappings/+page.svelte +219 -79
- package/build/client/_app/immutable/assets/0.CEIWAdGZ.css +0 -1
- package/build/client/_app/immutable/assets/0.CEIWAdGZ.css.br +0 -0
- package/build/client/_app/immutable/assets/0.CEIWAdGZ.css.gz +0 -0
- package/build/client/_app/immutable/assets/10.BrydhPds.css +0 -1
- package/build/client/_app/immutable/assets/10.BrydhPds.css.br +0 -0
- package/build/client/_app/immutable/assets/10.BrydhPds.css.gz +0 -0
- package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css.br +0 -0
- package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css.gz +0 -0
- package/build/client/_app/immutable/chunks/0oUK0vJa.js +0 -1
- package/build/client/_app/immutable/chunks/0oUK0vJa.js.br +0 -0
- package/build/client/_app/immutable/chunks/0oUK0vJa.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BGXqurs_.js +0 -1
- package/build/client/_app/immutable/chunks/BGXqurs_.js.br +0 -0
- package/build/client/_app/immutable/chunks/BGXqurs_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BO6_ugNx.js.br +0 -0
- package/build/client/_app/immutable/chunks/BO6_ugNx.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BPbCnJEo.js +0 -1
- package/build/client/_app/immutable/chunks/BPbCnJEo.js.br +0 -0
- package/build/client/_app/immutable/chunks/BPbCnJEo.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BXUq66wC.js.br +0 -0
- package/build/client/_app/immutable/chunks/BXUq66wC.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BxoAxRg6.js +0 -1
- package/build/client/_app/immutable/chunks/BxoAxRg6.js.br +0 -0
- package/build/client/_app/immutable/chunks/BxoAxRg6.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ByCRZ7zS.js +0 -2
- package/build/client/_app/immutable/chunks/ByCRZ7zS.js.br +0 -0
- package/build/client/_app/immutable/chunks/ByCRZ7zS.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BziC6PX1.js.br +0 -0
- package/build/client/_app/immutable/chunks/BziC6PX1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CpnIKQd1.js.br +0 -0
- package/build/client/_app/immutable/chunks/CpnIKQd1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DIw4Wyr4.js.br +0 -0
- package/build/client/_app/immutable/chunks/DIw4Wyr4.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DkI4PMxL.js.br +0 -0
- package/build/client/_app/immutable/chunks/DkI4PMxL.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dkr5ZtQR.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dkr5ZtQR.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DmXOK2q9.js +0 -16
- package/build/client/_app/immutable/chunks/DmXOK2q9.js.br +0 -0
- package/build/client/_app/immutable/chunks/DmXOK2q9.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dn0_-jEe.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dn0_-jEe.js.gz +0 -0
- package/build/client/_app/immutable/chunks/UJuWD2W4.js.br +0 -0
- package/build/client/_app/immutable/chunks/UJuWD2W4.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Z2a-si5C.js.br +0 -0
- package/build/client/_app/immutable/chunks/Z2a-si5C.js.gz +0 -0
- package/build/client/_app/immutable/chunks/_kKBJjiB.js +0 -1
- package/build/client/_app/immutable/chunks/_kKBJjiB.js.br +0 -0
- package/build/client/_app/immutable/chunks/_kKBJjiB.js.gz +0 -0
- package/build/client/_app/immutable/chunks/reNJcONQ.js.br +0 -0
- package/build/client/_app/immutable/chunks/s-K2chw6.js +0 -1
- package/build/client/_app/immutable/chunks/s-K2chw6.js.br +0 -0
- package/build/client/_app/immutable/chunks/s-K2chw6.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.BBGxwcK8.js +0 -2
- package/build/client/_app/immutable/entry/app.BBGxwcK8.js.br +0 -0
- package/build/client/_app/immutable/entry/app.BBGxwcK8.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.Cu5iaSNG.js +0 -1
- package/build/client/_app/immutable/entry/start.Cu5iaSNG.js.br +0 -0
- package/build/client/_app/immutable/entry/start.Cu5iaSNG.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.OznVrT12.js +0 -1
- package/build/client/_app/immutable/nodes/0.OznVrT12.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.OznVrT12.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.BnbJyDlh.js +0 -1
- package/build/client/_app/immutable/nodes/1.BnbJyDlh.js.br +0 -2
- package/build/client/_app/immutable/nodes/1.BnbJyDlh.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.4wMOwZtW.js +0 -3
- package/build/client/_app/immutable/nodes/10.4wMOwZtW.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.4wMOwZtW.js.gz +0 -0
- package/build/client/_app/immutable/nodes/11.IKyzjYy6.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.IKyzjYy6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/12.BYM9mUpP.js +0 -1
- package/build/client/_app/immutable/nodes/12.BYM9mUpP.js.br +0 -0
- package/build/client/_app/immutable/nodes/12.BYM9mUpP.js.gz +0 -0
- package/build/client/_app/immutable/nodes/13.ndMcrfHr.js +0 -66
- package/build/client/_app/immutable/nodes/13.ndMcrfHr.js.br +0 -0
- package/build/client/_app/immutable/nodes/13.ndMcrfHr.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.DqvBb3C7.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.DqvBb3C7.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.27swwcG4.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.27swwcG4.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.CcholrFe.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.CcholrFe.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.CzudN9q-.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.CzudN9q-.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.C560Uxhw.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.C560Uxhw.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.BEOgol-D.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.BEOgol-D.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.BmG9LqpS.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.BmG9LqpS.js.gz +0 -0
- package/build/server/chunks/0-DgHP79Ti.js +0 -22
- package/build/server/chunks/1--T1OTbjT.js +0 -9
- package/build/server/chunks/10-D1OhJt-m.js.map +0 -1
- package/build/server/chunks/JsonValue-Cexm3jGT.js.map +0 -1
- package/build/server/chunks/Modal-BzZ9u6V6.js.map +0 -1
- package/build/server/chunks/PrettyJson-tOt0PqjF.js.map +0 -1
- package/build/server/chunks/_layout.svelte-Dji2JJ9X.js.map +0 -1
- package/build/server/chunks/_page.svelte-CJ5HzoD0.js +0 -203
- package/build/server/chunks/_page.svelte-CJ5HzoD0.js.map +0 -1
- package/build/server/chunks/_page.svelte-D-23v2Aa.js.map +0 -1
- package/build/server/chunks/mongo-BHk5yAj9.js.map +0 -1
- package/build/server/chunks/remote-xxtqbu-ETLGkdRu.js.map +0 -1
- package/build/server/chunks/servers.remote-CGies_Na.js.map +0 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { resolve } from "$app/paths";
|
|
3
|
+
import IconExternalLink from "$lib/icons/IconExternalLink.svelte";
|
|
3
4
|
import type { MongoDocument } from "$lib/types";
|
|
4
5
|
import JsonValue from "./JsonValue.svelte";
|
|
5
6
|
import Tooltip from "./Tooltip.svelte";
|
|
6
7
|
|
|
7
8
|
const INDENT = " ";
|
|
8
9
|
|
|
10
|
+
import type { Mappings } from "$lib/types";
|
|
11
|
+
|
|
9
12
|
interface Props {
|
|
10
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
14
|
value: any;
|
|
@@ -24,6 +27,8 @@
|
|
|
24
27
|
) => Promise<{ document: MongoDocument | null; url: string | null; collection: string | null }>;
|
|
25
28
|
/** full path to current key (e.g., "user.address.city") */
|
|
26
29
|
keyPath?: string;
|
|
30
|
+
/** The mappings object */
|
|
31
|
+
mappings?: Mappings;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
let {
|
|
@@ -35,6 +40,7 @@
|
|
|
35
40
|
isKeyMapped,
|
|
36
41
|
fetchMappedDocument,
|
|
37
42
|
keyPath = "",
|
|
43
|
+
mappings,
|
|
38
44
|
}: Props = $props();
|
|
39
45
|
|
|
40
46
|
function getIndent(level: number): string {
|
|
@@ -57,6 +63,12 @@
|
|
|
57
63
|
// Check if current key has a mapping
|
|
58
64
|
const currentKeyPath = $derived([keyPath, key].filter(Boolean).join("."));
|
|
59
65
|
|
|
66
|
+
// Helper to interpolate URL template with value
|
|
67
|
+
function interpolateUrl(template: string, val: unknown): string {
|
|
68
|
+
const strValue = String(val);
|
|
69
|
+
return template.replace(/\{value\}/g, strValue);
|
|
70
|
+
}
|
|
71
|
+
|
|
60
72
|
async function handleMouseEnter() {
|
|
61
73
|
if (!hasMappings || !fetchMappedDocument) return;
|
|
62
74
|
|
|
@@ -146,7 +158,6 @@
|
|
|
146
158
|
|
|
147
159
|
const hasMappings = $derived(
|
|
148
160
|
!!isKeyMapped &&
|
|
149
|
-
!!fetchMappedDocument &&
|
|
150
161
|
key === undefined &&
|
|
151
162
|
isKeyMapped(currentKeyPath) &&
|
|
152
163
|
value !== null &&
|
|
@@ -155,6 +166,25 @@
|
|
|
155
166
|
valueType !== "object",
|
|
156
167
|
);
|
|
157
168
|
|
|
169
|
+
const hasCollectionMappings = $derived(hasMappings && !!fetchMappedDocument);
|
|
170
|
+
|
|
171
|
+
// Get URL mappings for current path
|
|
172
|
+
const urlMappings = $derived.by(() => {
|
|
173
|
+
if (!hasMappings || !mappings || !mappings[currentKeyPath]) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
const pathMappings = mappings[currentKeyPath];
|
|
177
|
+
const mappingsArray = Array.isArray(pathMappings) ? pathMappings : [pathMappings];
|
|
178
|
+
return mappingsArray.filter((m): m is { type: "url"; template: string } => {
|
|
179
|
+
if ("type" in m) {
|
|
180
|
+
return m.type === "url";
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const hasUrlMappings = $derived(urlMappings.length > 0);
|
|
187
|
+
|
|
158
188
|
let isCollapsible = $derived(valueType === "array" || valueType === "object");
|
|
159
189
|
let isEmpty = $derived(
|
|
160
190
|
(valueType === "array" && value.length === 0) || (valueType === "object" && Object.keys(value).length === 0),
|
|
@@ -189,6 +219,7 @@
|
|
|
189
219
|
{isKeyMapped}
|
|
190
220
|
{fetchMappedDocument}
|
|
191
221
|
keyPath={currentKeyPath}
|
|
222
|
+
{mappings}
|
|
192
223
|
/>
|
|
193
224
|
</span>
|
|
194
225
|
{:else}
|
|
@@ -218,6 +249,7 @@
|
|
|
218
249
|
{isKeyMapped}
|
|
219
250
|
{fetchMappedDocument}
|
|
220
251
|
keyPath={currentKeyPath}
|
|
252
|
+
{mappings}
|
|
221
253
|
/>
|
|
222
254
|
</span>
|
|
223
255
|
{/if}
|
|
@@ -231,6 +263,7 @@
|
|
|
231
263
|
{isKeyMapped}
|
|
232
264
|
{fetchMappedDocument}
|
|
233
265
|
keyPath={currentKeyPath}
|
|
266
|
+
{mappings}
|
|
234
267
|
/>
|
|
235
268
|
</span>
|
|
236
269
|
{/if}
|
|
@@ -281,6 +314,7 @@
|
|
|
281
314
|
keyPath={currentKeyPath}
|
|
282
315
|
{isKeyMapped}
|
|
283
316
|
{fetchMappedDocument}
|
|
317
|
+
{mappings}
|
|
284
318
|
/>{/each}
|
|
285
319
|
<br />{getIndent(depth)}
|
|
286
320
|
</span>{:else}
|
|
@@ -304,6 +338,7 @@
|
|
|
304
338
|
{isKeyMapped}
|
|
305
339
|
{fetchMappedDocument}
|
|
306
340
|
keyPath={currentKeyPath}
|
|
341
|
+
{mappings}
|
|
307
342
|
/>{/each}
|
|
308
343
|
</span>{/if}{#if collapsed}
|
|
309
344
|
<span class="collapsed-summary"
|
|
@@ -318,7 +353,21 @@
|
|
|
318
353
|
<span>{String(value)}</span>
|
|
319
354
|
{/if}
|
|
320
355
|
{/snippet}
|
|
321
|
-
{#if
|
|
356
|
+
{#if hasUrlMappings}
|
|
357
|
+
<!-- Render as external URL link(s) -->
|
|
358
|
+
<span class="string mapped url">
|
|
359
|
+
{#each urlMappings as urlMapping, i (i)}
|
|
360
|
+
{#if i > 0}
|
|
361
|
+
|
|
|
362
|
+
{/if}
|
|
363
|
+
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
|
364
|
+
<a href={interpolateUrl(urlMapping.template, value)} target="_blank" class="inline-flex items-center gap-1">
|
|
365
|
+
{@render valueSnippet?.()}
|
|
366
|
+
<IconExternalLink class="w-3 h-3 inline-block opacity-70" />
|
|
367
|
+
</a>
|
|
368
|
+
{/each}
|
|
369
|
+
</span>
|
|
370
|
+
{:else if hasCollectionMappings}
|
|
322
371
|
<Tooltip
|
|
323
372
|
show={showTooltip}
|
|
324
373
|
tooltipClass="max-w-[600px] max-h-[400px] overflow-auto whitespace-pre-wrap"
|
|
@@ -403,10 +452,6 @@
|
|
|
403
452
|
|
|
404
453
|
.collapsible-content {
|
|
405
454
|
white-space: pre;
|
|
406
|
-
|
|
407
|
-
&.hidden {
|
|
408
|
-
display: none;
|
|
409
|
-
}
|
|
410
455
|
}
|
|
411
456
|
|
|
412
457
|
.collapsed-summary {
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
show: boolean;
|
|
6
6
|
onclose: () => void;
|
|
7
7
|
title?: string;
|
|
8
|
+
wide?: boolean;
|
|
8
9
|
children?: Snippet;
|
|
9
10
|
footer?: Snippet;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
let { show = false, onclose, title, children, footer }: Props = $props();
|
|
13
|
+
let { show = false, onclose, title, wide = false, children, footer }: Props = $props();
|
|
13
14
|
|
|
14
15
|
function handleOverlayClick() {
|
|
15
16
|
onclose();
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
29
30
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
30
31
|
<div class="modal-overlay" onclick={handleOverlayClick}>
|
|
31
|
-
<div class="modal" onclick={(e) => e.stopPropagation()}>
|
|
32
|
+
<div class="modal" class:modal-wide={wide} onclick={(e) => e.stopPropagation()}>
|
|
32
33
|
{#if title}
|
|
33
34
|
<div class="modal-header">
|
|
34
35
|
<h3 style="color: var(--text);">{title}</h3>
|
|
@@ -56,4 +57,8 @@
|
|
|
56
57
|
font-size: 1.375rem;
|
|
57
58
|
font-weight: 600;
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
.modal-wide {
|
|
62
|
+
max-width: 800px;
|
|
63
|
+
}
|
|
59
64
|
</style>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import IconClose from "$lib/icons/IconClose.svelte";
|
|
2
3
|
import { notificationStore } from "$lib/stores/notifications.svelte";
|
|
3
4
|
</script>
|
|
4
5
|
|
|
@@ -7,20 +8,7 @@
|
|
|
7
8
|
<div class="notification notification-{notification.type}">
|
|
8
9
|
<span>{notification.message}</span>
|
|
9
10
|
<button onclick={() => notificationStore.remove(notification.id)} aria-label="Dismiss notification">
|
|
10
|
-
<
|
|
11
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
12
|
-
width="18"
|
|
13
|
-
height="18"
|
|
14
|
-
viewBox="0 0 24 24"
|
|
15
|
-
fill="none"
|
|
16
|
-
stroke="currentColor"
|
|
17
|
-
stroke-width="2"
|
|
18
|
-
stroke-linecap="round"
|
|
19
|
-
stroke-linejoin="round"
|
|
20
|
-
>
|
|
21
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
22
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
23
|
-
</svg>
|
|
11
|
+
<IconClose class="w-[18px] h-[18px]" />
|
|
24
12
|
</button>
|
|
25
13
|
</div>
|
|
26
14
|
{/each}
|
|
@@ -80,7 +68,7 @@
|
|
|
80
68
|
}
|
|
81
69
|
|
|
82
70
|
.notification-success {
|
|
83
|
-
background-color:
|
|
71
|
+
background-color: var(--button-success);
|
|
84
72
|
color: white;
|
|
85
73
|
}
|
|
86
74
|
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
<Panel class="group relative" title={json._id ? title : undefined} {actions} bind:ref={panelRef}>
|
|
246
246
|
<div bind:this={contentContainerRef} class="relative p-4 sm:p-6">
|
|
247
247
|
<div class="font-mono text-[13px] sm:text-[14px] leading-relaxed whitespace-pre-wrap break-words overflow-x-auto">
|
|
248
|
-
<JsonValue value={json} {autoCollapse} collapsed={false} {isKeyMapped} {fetchMappedDocument} />
|
|
248
|
+
<JsonValue value={json} {autoCollapse} collapsed={false} {isKeyMapped} {fetchMappedDocument} {mappings} />
|
|
249
249
|
</div>
|
|
250
250
|
|
|
251
251
|
{#if removing}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { countDocumentsByTimeRange } from "$api/servers.remote";
|
|
2
3
|
import { goto } from "$app/navigation";
|
|
3
4
|
import { resolve } from "$app/paths";
|
|
4
5
|
import { page } from "$app/state";
|
|
@@ -8,15 +9,30 @@
|
|
|
8
9
|
import IconChevronDown from "$lib/icons/IconChevronDown.svelte";
|
|
9
10
|
import IconEdit from "$lib/icons/IconEdit.svelte";
|
|
10
11
|
import type { SearchParams } from "$lib/types";
|
|
12
|
+
import { formatNumber } from "$lib/utils/filters";
|
|
11
13
|
import { tick } from "svelte";
|
|
12
14
|
|
|
13
15
|
interface Props {
|
|
14
16
|
params: SearchParams;
|
|
15
17
|
editMode?: boolean;
|
|
16
18
|
readonly: boolean;
|
|
19
|
+
explainLoading?: boolean;
|
|
20
|
+
onexplain?: () => void;
|
|
21
|
+
server?: string;
|
|
22
|
+
database?: string;
|
|
23
|
+
collection?: string;
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
let {
|
|
26
|
+
let {
|
|
27
|
+
params = $bindable(),
|
|
28
|
+
editMode = $bindable(false),
|
|
29
|
+
readonly = $bindable(false),
|
|
30
|
+
explainLoading = false,
|
|
31
|
+
onexplain,
|
|
32
|
+
server,
|
|
33
|
+
database,
|
|
34
|
+
collection,
|
|
35
|
+
}: Props = $props();
|
|
20
36
|
|
|
21
37
|
// Show optional fields - start with all hidden
|
|
22
38
|
let showOptionalFields = $state(
|
|
@@ -103,6 +119,83 @@
|
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
let form = $state<HTMLFormElement | undefined>(undefined);
|
|
122
|
+
|
|
123
|
+
// New Docs dropdown state
|
|
124
|
+
const TIME_RANGES = [
|
|
125
|
+
{ label: "Last 24 hours", days: 1 },
|
|
126
|
+
{ label: "Last 7 days", days: 7 },
|
|
127
|
+
{ label: "Last 30 days", days: 30 },
|
|
128
|
+
{ label: "Last 90 days", days: 90 },
|
|
129
|
+
{ label: "Last 180 days", days: 180 },
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
let showNewDocsDropdown = $state(false);
|
|
133
|
+
let newDocsButtonElement = $state<HTMLButtonElement>();
|
|
134
|
+
let newDocsDropdownPosition = $state({ left: "0px", top: "0px", minWidth: "200px" });
|
|
135
|
+
let isStatsLoading = $state(false);
|
|
136
|
+
let stats = $state<Array<{ label: string; days: number; count: number | null; error: string | null }> | null>(null);
|
|
137
|
+
|
|
138
|
+
// Calculate New Docs dropdown position when shown
|
|
139
|
+
$effect(() => {
|
|
140
|
+
if (showNewDocsDropdown && newDocsButtonElement) {
|
|
141
|
+
tick().then(() => {
|
|
142
|
+
if (!newDocsButtonElement) return;
|
|
143
|
+
const rect = newDocsButtonElement.getBoundingClientRect();
|
|
144
|
+
newDocsDropdownPosition = {
|
|
145
|
+
left: `${rect.right - 200}px`,
|
|
146
|
+
top: `${rect.bottom + 5}px`,
|
|
147
|
+
minWidth: "200px",
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
async function loadStats() {
|
|
154
|
+
if (!server || !database || !collection || isStatsLoading) return;
|
|
155
|
+
|
|
156
|
+
isStatsLoading = true;
|
|
157
|
+
try {
|
|
158
|
+
const result = await countDocumentsByTimeRange({
|
|
159
|
+
server,
|
|
160
|
+
database,
|
|
161
|
+
collection,
|
|
162
|
+
timeRanges: TIME_RANGES,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (!result.error) {
|
|
166
|
+
stats = result.data;
|
|
167
|
+
}
|
|
168
|
+
} finally {
|
|
169
|
+
isStatsLoading = false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function toggleNewDocsDropdown() {
|
|
174
|
+
showNewDocsDropdown = !showNewDocsDropdown;
|
|
175
|
+
if (showNewDocsDropdown && stats === null) {
|
|
176
|
+
loadStats();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function selectTimeRange(days: number) {
|
|
181
|
+
// Calculate the ObjectId for X days ago
|
|
182
|
+
const now = Date.now();
|
|
183
|
+
const daysInMs = days * 24 * 60 * 60 * 1000;
|
|
184
|
+
const timestamp = Math.floor((now - daysInMs) / 1000);
|
|
185
|
+
|
|
186
|
+
// Create ObjectId hex string from timestamp (first 4 bytes are timestamp)
|
|
187
|
+
const objectIdHex = timestamp.toString(16).padStart(8, "0") + "0000000000000000";
|
|
188
|
+
|
|
189
|
+
// Set the query with the ObjectId filter
|
|
190
|
+
params.query = `{_id: {$gte: ObjectId("${objectIdHex}")}}`;
|
|
191
|
+
params.mode = "query";
|
|
192
|
+
showNewDocsDropdown = false;
|
|
193
|
+
|
|
194
|
+
tick().then(() => {
|
|
195
|
+
// Submit the form
|
|
196
|
+
form?.requestSubmit();
|
|
197
|
+
});
|
|
198
|
+
}
|
|
106
199
|
</script>
|
|
107
200
|
|
|
108
201
|
<div class="rounded-2xl border border-[var(--border-color)] bg-[var(--light-background)]/70 shadow-sm p-3 sm:p-4">
|
|
@@ -161,6 +254,19 @@
|
|
|
161
254
|
<input type="hidden" value={counter} name="v" />
|
|
162
255
|
|
|
163
256
|
<div class="flex items-center gap-2">
|
|
257
|
+
{#if server && database && collection}
|
|
258
|
+
<button
|
|
259
|
+
type="button"
|
|
260
|
+
bind:this={newDocsButtonElement}
|
|
261
|
+
class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] transition cursor-pointer text-[13px] font-medium flex items-center gap-1"
|
|
262
|
+
style="color: var(--text-secondary);"
|
|
263
|
+
title="Filter by document creation time"
|
|
264
|
+
onclick={toggleNewDocsDropdown}
|
|
265
|
+
>
|
|
266
|
+
<span>📊</span>
|
|
267
|
+
<IconChevronDown class="w-3 h-3" />
|
|
268
|
+
</button>
|
|
269
|
+
{/if}
|
|
164
270
|
<button
|
|
165
271
|
type="button"
|
|
166
272
|
class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] text-[15px] font-semibold leading-none transition cursor-pointer"
|
|
@@ -186,10 +292,21 @@
|
|
|
186
292
|
<IconEdit class="w-4 h-4" />
|
|
187
293
|
</button>
|
|
188
294
|
{/if}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
295
|
+
{#if onexplain}
|
|
296
|
+
<button
|
|
297
|
+
type="button"
|
|
298
|
+
class="h-9 px-3 rounded-xl border border-[var(--border-color)] bg-[var(--light-background)] hover:bg-[var(--color-3)] transition disabled:opacity-50 cursor-pointer text-[13px] font-medium"
|
|
299
|
+
style="color: var(--link);"
|
|
300
|
+
title={params.mode === "distinct"
|
|
301
|
+
? "Explain not available for distinct queries"
|
|
302
|
+
: "Show query execution plan"}
|
|
303
|
+
disabled={params.mode === "distinct" || explainLoading}
|
|
304
|
+
onclick={onexplain}
|
|
305
|
+
>
|
|
306
|
+
{explainLoading ? "..." : "Explain"}
|
|
307
|
+
</button>
|
|
308
|
+
{/if}
|
|
309
|
+
<button type="submit" class="h-9 px-4 py-0 rounded-xl btn btn-success text-lg font-semibold transition">
|
|
193
310
|
Go
|
|
194
311
|
</button>
|
|
195
312
|
</div>
|
|
@@ -335,6 +452,44 @@
|
|
|
335
452
|
</div>
|
|
336
453
|
{/if}
|
|
337
454
|
|
|
455
|
+
<!-- New Docs dropdown (rendered via portal to avoid overflow issues) -->
|
|
456
|
+
{#if showNewDocsDropdown}
|
|
457
|
+
<div
|
|
458
|
+
use:portal
|
|
459
|
+
use:clickOutside={() => (showNewDocsDropdown = false)}
|
|
460
|
+
class="fixed z-[1000] rounded-lg border border-[var(--border-color)] bg-[var(--light-background)] shadow-lg overflow-hidden"
|
|
461
|
+
style:left={newDocsDropdownPosition.left}
|
|
462
|
+
style:top={newDocsDropdownPosition.top}
|
|
463
|
+
style:min-width={newDocsDropdownPosition.minWidth}
|
|
464
|
+
>
|
|
465
|
+
{#if isStatsLoading}
|
|
466
|
+
<div class="px-3 py-2 text-[13px]" style="color: var(--text-secondary);">Loading...</div>
|
|
467
|
+
{:else if stats && stats.length > 0}
|
|
468
|
+
{#each stats as stat (stat.label)}
|
|
469
|
+
<button
|
|
470
|
+
type="button"
|
|
471
|
+
class="w-full px-3 py-2 text-left text-[13px] hover:bg-[var(--color-3)] transition cursor-pointer flex justify-between items-center"
|
|
472
|
+
style="color: var(--text);"
|
|
473
|
+
onclick={() => selectTimeRange(stat.days)}
|
|
474
|
+
>
|
|
475
|
+
<span>{stat.label}</span>
|
|
476
|
+
<span class="font-medium tabular-nums" style="color: var(--text-secondary);">
|
|
477
|
+
{#if stat.error}
|
|
478
|
+
⚠️
|
|
479
|
+
{:else if stat.count !== null}
|
|
480
|
+
{formatNumber(stat.count)}
|
|
481
|
+
{:else}
|
|
482
|
+
—
|
|
483
|
+
{/if}
|
|
484
|
+
</span>
|
|
485
|
+
</button>
|
|
486
|
+
{/each}
|
|
487
|
+
{:else}
|
|
488
|
+
<div class="px-3 py-2 text-[13px]" style="color: var(--text-secondary);">No data available</div>
|
|
489
|
+
{/if}
|
|
490
|
+
</div>
|
|
491
|
+
{/if}
|
|
492
|
+
|
|
338
493
|
<style lang="postcss">
|
|
339
494
|
input[type="text"],
|
|
340
495
|
input[type="number"],
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { countDocumentsByTimeRange } from "$api/servers.remote";
|
|
3
|
+
import IconChevronDown from "$lib/icons/IconChevronDown.svelte";
|
|
4
|
+
import { formatNumber } from "$lib/utils/filters";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
server: string;
|
|
8
|
+
database: string;
|
|
9
|
+
collection: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let { server, database, collection }: Props = $props();
|
|
13
|
+
|
|
14
|
+
const TIME_RANGES = [
|
|
15
|
+
{ label: "Last 24 hours", days: 1 },
|
|
16
|
+
{ label: "Last 7 days", days: 7 },
|
|
17
|
+
{ label: "Last 30 days", days: 30 },
|
|
18
|
+
{ label: "Last 90 days", days: 90 },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
let isOpen = $state(false);
|
|
22
|
+
let isLoading = $state(false);
|
|
23
|
+
let stats = $state<Array<{ label: string; days: number; count: number | null; error: string | null }> | null>(null);
|
|
24
|
+
let loadError = $state<string | null>(null);
|
|
25
|
+
|
|
26
|
+
async function loadStats() {
|
|
27
|
+
if (stats !== null || isLoading) return;
|
|
28
|
+
|
|
29
|
+
isLoading = true;
|
|
30
|
+
loadError = null;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const result = await countDocumentsByTimeRange({
|
|
34
|
+
server,
|
|
35
|
+
database,
|
|
36
|
+
collection,
|
|
37
|
+
timeRanges: TIME_RANGES,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (result.error) {
|
|
41
|
+
loadError = result.error;
|
|
42
|
+
} else {
|
|
43
|
+
stats = result.data;
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
loadError = err instanceof Error ? err.message : String(err);
|
|
47
|
+
} finally {
|
|
48
|
+
isLoading = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function toggle() {
|
|
53
|
+
isOpen = !isOpen;
|
|
54
|
+
if (isOpen && stats === null) {
|
|
55
|
+
loadStats();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function refresh() {
|
|
60
|
+
stats = null;
|
|
61
|
+
loadStats();
|
|
62
|
+
}
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<div class="time-range-stats">
|
|
66
|
+
<button class="toggle-btn" onclick={toggle} aria-expanded={isOpen} aria-label="Toggle new documents statistics">
|
|
67
|
+
<span class="icon">📊</span>
|
|
68
|
+
<span class="label">New Documents</span>
|
|
69
|
+
<IconChevronDown class="chevron {isOpen ? 'rotate' : ''}" />
|
|
70
|
+
</button>
|
|
71
|
+
|
|
72
|
+
{#if isOpen}
|
|
73
|
+
<div class="stats-panel">
|
|
74
|
+
{#if isLoading}
|
|
75
|
+
<div class="loading">
|
|
76
|
+
<span class="spinner"></span>
|
|
77
|
+
<span>Loading statistics...</span>
|
|
78
|
+
</div>
|
|
79
|
+
{:else if loadError}
|
|
80
|
+
<div class="error">
|
|
81
|
+
<span>⚠️ {loadError}</span>
|
|
82
|
+
<button class="retry-btn" onclick={refresh}>Retry</button>
|
|
83
|
+
</div>
|
|
84
|
+
{:else if stats}
|
|
85
|
+
<div class="stats-grid">
|
|
86
|
+
{#each stats as stat (stat.label)}
|
|
87
|
+
<div class="stat-item">
|
|
88
|
+
<div class="stat-label">{stat.label}</div>
|
|
89
|
+
<div class="stat-value">
|
|
90
|
+
{#if stat.error}
|
|
91
|
+
<span class="stat-error" title={stat.error}>⚠️</span>
|
|
92
|
+
{:else if stat.count !== null}
|
|
93
|
+
<span class="count">{formatNumber(stat.count)}</span>
|
|
94
|
+
<span class="docs">docs</span>
|
|
95
|
+
{:else}
|
|
96
|
+
<span class="stat-error">—</span>
|
|
97
|
+
{/if}
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
{/each}
|
|
101
|
+
</div>
|
|
102
|
+
<button class="refresh-btn" onclick={refresh} title="Refresh statistics"> 🔄 </button>
|
|
103
|
+
{/if}
|
|
104
|
+
</div>
|
|
105
|
+
{/if}
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<style>
|
|
109
|
+
.time-range-stats {
|
|
110
|
+
position: relative;
|
|
111
|
+
margin-bottom: 1rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.toggle-btn {
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
gap: 0.5rem;
|
|
118
|
+
padding: 0.5rem 1rem;
|
|
119
|
+
background: var(--light-background);
|
|
120
|
+
border: 1px solid var(--border-color);
|
|
121
|
+
border-radius: 0.75rem;
|
|
122
|
+
color: var(--text);
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
font-size: 0.875rem;
|
|
125
|
+
font-weight: 500;
|
|
126
|
+
transition: all 0.2s ease;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.toggle-btn:hover {
|
|
130
|
+
background: var(--color-3);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.icon {
|
|
134
|
+
font-size: 1rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.label {
|
|
138
|
+
color: var(--text);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
:global(.chevron) {
|
|
142
|
+
width: 1rem;
|
|
143
|
+
height: 1rem;
|
|
144
|
+
transition: transform 0.2s ease;
|
|
145
|
+
color: var(--text-secondary);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
:global(.chevron.rotate) {
|
|
149
|
+
transform: rotate(180deg);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.stats-panel {
|
|
153
|
+
position: absolute;
|
|
154
|
+
top: 100%;
|
|
155
|
+
left: 0;
|
|
156
|
+
z-index: 50;
|
|
157
|
+
margin-top: 0.5rem;
|
|
158
|
+
padding: 1rem;
|
|
159
|
+
background: var(--background);
|
|
160
|
+
border: 1px solid var(--border-color);
|
|
161
|
+
border-radius: 0.75rem;
|
|
162
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
163
|
+
min-width: 280px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.loading {
|
|
167
|
+
display: flex;
|
|
168
|
+
align-items: center;
|
|
169
|
+
gap: 0.75rem;
|
|
170
|
+
color: var(--text-secondary);
|
|
171
|
+
font-size: 0.875rem;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.spinner {
|
|
175
|
+
width: 1rem;
|
|
176
|
+
height: 1rem;
|
|
177
|
+
border: 2px solid var(--border-color);
|
|
178
|
+
border-top-color: var(--link);
|
|
179
|
+
border-radius: 50%;
|
|
180
|
+
animation: spin 0.8s linear infinite;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@keyframes spin {
|
|
184
|
+
to {
|
|
185
|
+
transform: rotate(360deg);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.error {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: space-between;
|
|
193
|
+
gap: 0.75rem;
|
|
194
|
+
color: var(--error);
|
|
195
|
+
font-size: 0.875rem;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.retry-btn {
|
|
199
|
+
padding: 0.25rem 0.75rem;
|
|
200
|
+
background: var(--color-3);
|
|
201
|
+
border: 1px solid var(--border-color);
|
|
202
|
+
border-radius: 0.5rem;
|
|
203
|
+
color: var(--text);
|
|
204
|
+
cursor: pointer;
|
|
205
|
+
font-size: 0.75rem;
|
|
206
|
+
transition: background 0.2s ease;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.retry-btn:hover {
|
|
210
|
+
background: var(--light-background);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.stats-grid {
|
|
214
|
+
display: grid;
|
|
215
|
+
grid-template-columns: repeat(2, 1fr);
|
|
216
|
+
gap: 0.75rem;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.stat-item {
|
|
220
|
+
padding: 0.75rem;
|
|
221
|
+
background: var(--color-3);
|
|
222
|
+
border-radius: 0.5rem;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.stat-label {
|
|
226
|
+
font-size: 0.75rem;
|
|
227
|
+
color: var(--text-secondary);
|
|
228
|
+
margin-bottom: 0.25rem;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.stat-value {
|
|
232
|
+
display: flex;
|
|
233
|
+
align-items: baseline;
|
|
234
|
+
gap: 0.25rem;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.count {
|
|
238
|
+
font-size: 1.25rem;
|
|
239
|
+
font-weight: 600;
|
|
240
|
+
color: var(--text);
|
|
241
|
+
font-variant-numeric: tabular-nums;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.docs {
|
|
245
|
+
font-size: 0.75rem;
|
|
246
|
+
color: var(--text-secondary);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.stat-error {
|
|
250
|
+
color: var(--error);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.refresh-btn {
|
|
254
|
+
position: absolute;
|
|
255
|
+
top: 0.5rem;
|
|
256
|
+
right: 0.5rem;
|
|
257
|
+
padding: 0.25rem;
|
|
258
|
+
background: transparent;
|
|
259
|
+
border: none;
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
font-size: 0.875rem;
|
|
262
|
+
opacity: 0.6;
|
|
263
|
+
transition: opacity 0.2s ease;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.refresh-btn:hover {
|
|
267
|
+
opacity: 1;
|
|
268
|
+
}
|
|
269
|
+
</style>
|