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.
Files changed (300) hide show
  1. package/README.md +15 -0
  2. package/build/client/_app/immutable/assets/0.C_geP4pp.css +1 -0
  3. package/build/client/_app/immutable/assets/0.C_geP4pp.css.br +0 -0
  4. package/build/client/_app/immutable/assets/0.C_geP4pp.css.gz +0 -0
  5. package/build/client/_app/immutable/assets/10.Wc4MTSzM.css +1 -0
  6. package/build/client/_app/immutable/assets/10.Wc4MTSzM.css.br +0 -0
  7. package/build/client/_app/immutable/assets/10.Wc4MTSzM.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/{Modal.zD4dMMyk.css → Modal.CZgFKXkP.css} +1 -1
  9. package/build/client/_app/immutable/assets/Modal.CZgFKXkP.css.br +0 -0
  10. package/build/client/_app/immutable/assets/Modal.CZgFKXkP.css.gz +0 -0
  11. package/build/client/_app/immutable/chunks/B27BoO92.js +1 -0
  12. package/build/client/_app/immutable/chunks/B27BoO92.js.br +0 -0
  13. package/build/client/_app/immutable/chunks/B27BoO92.js.gz +0 -0
  14. package/build/client/_app/immutable/chunks/{reNJcONQ.js → BLB7WU0x.js} +1 -1
  15. package/build/client/_app/immutable/chunks/BLB7WU0x.js.br +0 -0
  16. package/build/client/_app/immutable/chunks/{reNJcONQ.js.gz → BLB7WU0x.js.gz} +0 -0
  17. package/build/client/_app/immutable/chunks/{Dkr5ZtQR.js → BTDPx7wo.js} +1 -1
  18. package/build/client/_app/immutable/chunks/BTDPx7wo.js.br +0 -0
  19. package/build/client/_app/immutable/chunks/BTDPx7wo.js.gz +0 -0
  20. package/build/client/_app/immutable/chunks/{BziC6PX1.js → BV1jCwWf.js} +1 -1
  21. package/build/client/_app/immutable/chunks/BV1jCwWf.js.br +0 -0
  22. package/build/client/_app/immutable/chunks/BV1jCwWf.js.gz +0 -0
  23. package/build/client/_app/immutable/chunks/Bp2iD_PL.js +1 -0
  24. package/build/client/_app/immutable/chunks/Bp2iD_PL.js.br +0 -0
  25. package/build/client/_app/immutable/chunks/Bp2iD_PL.js.gz +0 -0
  26. package/build/client/_app/immutable/chunks/CItzKczS.js +1 -0
  27. package/build/client/_app/immutable/chunks/CItzKczS.js.br +0 -0
  28. package/build/client/_app/immutable/chunks/CItzKczS.js.gz +0 -0
  29. package/build/client/_app/immutable/chunks/{BO6_ugNx.js → Ce084HhL.js} +1 -1
  30. package/build/client/_app/immutable/chunks/Ce084HhL.js.br +0 -0
  31. package/build/client/_app/immutable/chunks/Ce084HhL.js.gz +0 -0
  32. package/build/client/_app/immutable/chunks/{DIw4Wyr4.js → CqFYS5AV.js} +1 -1
  33. package/build/client/_app/immutable/chunks/CqFYS5AV.js.br +0 -0
  34. package/build/client/_app/immutable/chunks/CqFYS5AV.js.gz +0 -0
  35. package/build/client/_app/immutable/chunks/{CpnIKQd1.js → DC13l09X.js} +6 -6
  36. package/build/client/_app/immutable/chunks/DC13l09X.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/DC13l09X.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/{DkI4PMxL.js → DXWJTsg6.js} +1 -1
  39. package/build/client/_app/immutable/chunks/DXWJTsg6.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/DXWJTsg6.js.gz +0 -0
  41. package/build/client/_app/immutable/chunks/Dip-8jE5.js +1 -0
  42. package/build/client/_app/immutable/chunks/Dip-8jE5.js.br +0 -0
  43. package/build/client/_app/immutable/chunks/Dip-8jE5.js.gz +0 -0
  44. package/build/client/_app/immutable/chunks/Dr_XE7iR.js +2 -0
  45. package/build/client/_app/immutable/chunks/Dr_XE7iR.js.br +0 -0
  46. package/build/client/_app/immutable/chunks/Dr_XE7iR.js.gz +0 -0
  47. package/build/client/_app/immutable/chunks/DuLpG1zT.js +1 -0
  48. package/build/client/_app/immutable/chunks/DuLpG1zT.js.br +0 -0
  49. package/build/client/_app/immutable/chunks/DuLpG1zT.js.gz +0 -0
  50. package/build/client/_app/immutable/chunks/{Dn0_-jEe.js → DyfVYlRP.js} +1 -1
  51. package/build/client/_app/immutable/chunks/DyfVYlRP.js.br +0 -0
  52. package/build/client/_app/immutable/chunks/DyfVYlRP.js.gz +0 -0
  53. package/build/client/_app/immutable/chunks/{BXUq66wC.js → OTbFjzBQ.js} +1 -1
  54. package/build/client/_app/immutable/chunks/OTbFjzBQ.js.br +0 -0
  55. package/build/client/_app/immutable/chunks/OTbFjzBQ.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/{UJuWD2W4.js → TQ9V_LBO.js} +1 -1
  57. package/build/client/_app/immutable/chunks/TQ9V_LBO.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/TQ9V_LBO.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/{Z2a-si5C.js → p4lxgeXU.js} +3 -3
  60. package/build/client/_app/immutable/chunks/p4lxgeXU.js.br +0 -0
  61. package/build/client/_app/immutable/chunks/p4lxgeXU.js.gz +0 -0
  62. package/build/client/_app/immutable/chunks/pXcSrKpr.js +1 -0
  63. package/build/client/_app/immutable/chunks/pXcSrKpr.js.br +0 -0
  64. package/build/client/_app/immutable/chunks/pXcSrKpr.js.gz +0 -0
  65. package/build/client/_app/immutable/chunks/xuMwtvm-.js +16 -0
  66. package/build/client/_app/immutable/chunks/xuMwtvm-.js.br +0 -0
  67. package/build/client/_app/immutable/chunks/xuMwtvm-.js.gz +0 -0
  68. package/build/client/_app/immutable/entry/app.B7JBkmJ2.js +2 -0
  69. package/build/client/_app/immutable/entry/app.B7JBkmJ2.js.br +0 -0
  70. package/build/client/_app/immutable/entry/app.B7JBkmJ2.js.gz +0 -0
  71. package/build/client/_app/immutable/entry/start.C35Eiz23.js +1 -0
  72. package/build/client/_app/immutable/entry/start.C35Eiz23.js.br +2 -0
  73. package/build/client/_app/immutable/entry/start.C35Eiz23.js.gz +0 -0
  74. package/build/client/_app/immutable/nodes/0.U3Wc2t11.js +1 -0
  75. package/build/client/_app/immutable/nodes/0.U3Wc2t11.js.br +0 -0
  76. package/build/client/_app/immutable/nodes/0.U3Wc2t11.js.gz +0 -0
  77. package/build/client/_app/immutable/nodes/1.YN6Ljj2X.js +1 -0
  78. package/build/client/_app/immutable/nodes/1.YN6Ljj2X.js.br +2 -0
  79. package/build/client/_app/immutable/nodes/1.YN6Ljj2X.js.gz +0 -0
  80. package/build/client/_app/immutable/nodes/10.E5c2rVVT.js +3 -0
  81. package/build/client/_app/immutable/nodes/10.E5c2rVVT.js.br +0 -0
  82. package/build/client/_app/immutable/nodes/10.E5c2rVVT.js.gz +0 -0
  83. package/build/client/_app/immutable/nodes/{11.IKyzjYy6.js → 11.CwiIDBVl.js} +1 -1
  84. package/build/client/_app/immutable/nodes/11.CwiIDBVl.js.br +0 -0
  85. package/build/client/_app/immutable/nodes/11.CwiIDBVl.js.gz +0 -0
  86. package/build/client/_app/immutable/nodes/12.BF4KBraU.js +1 -0
  87. package/build/client/_app/immutable/nodes/12.BF4KBraU.js.br +0 -0
  88. package/build/client/_app/immutable/nodes/12.BF4KBraU.js.gz +0 -0
  89. package/build/client/_app/immutable/nodes/13.BNgciqug.js +65 -0
  90. package/build/client/_app/immutable/nodes/13.BNgciqug.js.br +0 -0
  91. package/build/client/_app/immutable/nodes/13.BNgciqug.js.gz +0 -0
  92. package/build/client/_app/immutable/nodes/{2.DqvBb3C7.js → 2.Byf6opOr.js} +1 -1
  93. package/build/client/_app/immutable/nodes/2.Byf6opOr.js.br +0 -0
  94. package/build/client/_app/immutable/nodes/2.Byf6opOr.js.gz +0 -0
  95. package/build/client/_app/immutable/nodes/{3.27swwcG4.js → 3.B3j0bAgy.js} +1 -1
  96. package/build/client/_app/immutable/nodes/3.B3j0bAgy.js.br +0 -0
  97. package/build/client/_app/immutable/nodes/3.B3j0bAgy.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/{4.CcholrFe.js → 4.6dtz57ii.js} +1 -1
  99. package/build/client/_app/immutable/nodes/4.6dtz57ii.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/4.6dtz57ii.js.gz +0 -0
  101. package/build/client/_app/immutable/nodes/{5.CzudN9q-.js → 5.COHVaEDo.js} +1 -1
  102. package/build/client/_app/immutable/nodes/5.COHVaEDo.js.br +0 -0
  103. package/build/client/_app/immutable/nodes/5.COHVaEDo.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/{7.C560Uxhw.js → 7.Cecp1nCH.js} +1 -1
  105. package/build/client/_app/immutable/nodes/7.Cecp1nCH.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/7.Cecp1nCH.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/{8.BEOgol-D.js → 8.DFk2Y9sL.js} +1 -1
  108. package/build/client/_app/immutable/nodes/8.DFk2Y9sL.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/8.DFk2Y9sL.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/{9.BmG9LqpS.js → 9.W4l2xsEF.js} +1 -1
  111. package/build/client/_app/immutable/nodes/9.W4l2xsEF.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/9.W4l2xsEF.js.gz +0 -0
  113. package/build/client/_app/version.json +1 -1
  114. package/build/client/_app/version.json.br +0 -0
  115. package/build/client/_app/version.json.gz +0 -0
  116. package/build/server/chunks/0-CuiS31Ys.js +22 -0
  117. package/build/server/chunks/{0-DgHP79Ti.js.map → 0-CuiS31Ys.js.map} +1 -1
  118. package/build/server/chunks/1-C9TxPuQ0.js +9 -0
  119. package/build/server/chunks/{1--T1OTbjT.js.map → 1-C9TxPuQ0.js.map} +1 -1
  120. package/build/server/chunks/{10-D1OhJt-m.js → 10-PX9d-jhv.js} +5 -5
  121. package/build/server/chunks/10-PX9d-jhv.js.map +1 -0
  122. package/build/server/chunks/{11-pr9S-VkT.js → 11-Bhv-UeEo.js} +4 -4
  123. package/build/server/chunks/{11-pr9S-VkT.js.map → 11-Bhv-UeEo.js.map} +1 -1
  124. package/build/server/chunks/{12-B_w9udgo.js → 12-BuNmW-Vp.js} +5 -5
  125. package/build/server/chunks/{12-B_w9udgo.js.map → 12-BuNmW-Vp.js.map} +1 -1
  126. package/build/server/chunks/{13-CfrLQ4p0.js → 13-CAI7Pyhf.js} +4 -4
  127. package/build/server/chunks/{13-CfrLQ4p0.js.map → 13-CAI7Pyhf.js.map} +1 -1
  128. package/build/server/chunks/{2-BheEgghx.js → 2-Bx656tbc.js} +2 -2
  129. package/build/server/chunks/{2-BheEgghx.js.map → 2-Bx656tbc.js.map} +1 -1
  130. package/build/server/chunks/{3-BwrTscBH.js → 3-B-zRiOJV.js} +2 -2
  131. package/build/server/chunks/{3-BwrTscBH.js.map → 3-B-zRiOJV.js.map} +1 -1
  132. package/build/server/chunks/{4-D28kbpdN.js → 4-BBCE4OIo.js} +2 -2
  133. package/build/server/chunks/{4-D28kbpdN.js.map → 4-BBCE4OIo.js.map} +1 -1
  134. package/build/server/chunks/{5--wY8V1OC.js → 5-D68X5smv.js} +2 -2
  135. package/build/server/chunks/{5--wY8V1OC.js.map → 5-D68X5smv.js.map} +1 -1
  136. package/build/server/chunks/{7-9IXFVUUl.js → 7-C8AZjmDc.js} +4 -4
  137. package/build/server/chunks/{7-9IXFVUUl.js.map → 7-C8AZjmDc.js.map} +1 -1
  138. package/build/server/chunks/{8-DQQl8f10.js → 8-CGRiuqYX.js} +5 -5
  139. package/build/server/chunks/{8-DQQl8f10.js.map → 8-CGRiuqYX.js.map} +1 -1
  140. package/build/server/chunks/{9-B4xWo186.js → 9-CBzIf4Vj.js} +5 -5
  141. package/build/server/chunks/{9-B4xWo186.js.map → 9-CBzIf4Vj.js.map} +1 -1
  142. package/build/server/chunks/{JsonValue-Cexm3jGT.js → JsonValue-EppVzWzE.js} +88 -36
  143. package/build/server/chunks/JsonValue-EppVzWzE.js.map +1 -0
  144. package/build/server/chunks/{Modal-BzZ9u6V6.js → Modal-eRpc5lqR.js} +4 -3
  145. package/build/server/chunks/Modal-eRpc5lqR.js.map +1 -0
  146. package/build/server/chunks/{Panel-BHGtM9Vw.js → Panel-HO9t9Spv.js} +2 -2
  147. package/build/server/chunks/{Panel-BHGtM9Vw.js.map → Panel-HO9t9Spv.js.map} +1 -1
  148. package/build/server/chunks/{PrettyJson-tOt0PqjF.js → PrettyJson-F3fqxkqU.js} +7 -6
  149. package/build/server/chunks/PrettyJson-F3fqxkqU.js.map +1 -0
  150. package/build/server/chunks/{Tooltip-DAE2mkm6.js → Tooltip-Dd-Bzogp.js} +2 -2
  151. package/build/server/chunks/{Tooltip-DAE2mkm6.js.map → Tooltip-Dd-Bzogp.js.map} +1 -1
  152. package/build/server/chunks/{TooltipTable-xo_OEG9c.js → TooltipTable-jHWezlEs.js} +3 -3
  153. package/build/server/chunks/{TooltipTable-xo_OEG9c.js.map → TooltipTable-jHWezlEs.js.map} +1 -1
  154. package/build/server/chunks/{_layout.svelte-Dji2JJ9X.js → _layout.svelte-CKGgUBvr.js} +9 -3
  155. package/build/server/chunks/_layout.svelte-CKGgUBvr.js.map +1 -0
  156. package/build/server/chunks/_page.svelte-BlmdSnTh.js +245 -0
  157. package/build/server/chunks/_page.svelte-BlmdSnTh.js.map +1 -0
  158. package/build/server/chunks/{_page.svelte-x1L5xjgQ.js → _page.svelte-ClZj6yzK.js} +7 -7
  159. package/build/server/chunks/{_page.svelte-x1L5xjgQ.js.map → _page.svelte-ClZj6yzK.js.map} +1 -1
  160. package/build/server/chunks/{_page.svelte-be8sxgGt.js → _page.svelte-D50SWEhd.js} +8 -8
  161. package/build/server/chunks/{_page.svelte-be8sxgGt.js.map → _page.svelte-D50SWEhd.js.map} +1 -1
  162. package/build/server/chunks/{_page.svelte-D-23v2Aa.js → _page.svelte-D8GSKYqN.js} +223 -12
  163. package/build/server/chunks/_page.svelte-D8GSKYqN.js.map +1 -0
  164. package/build/server/chunks/{_page.svelte-D9IvgJO5.js → _page.svelte-DBcsXxML.js} +8 -8
  165. package/build/server/chunks/{_page.svelte-D9IvgJO5.js.map → _page.svelte-DBcsXxML.js.map} +1 -1
  166. package/build/server/chunks/{_page.svelte-aT9hOnbL.js → _page.svelte-DFzKfImt.js} +8 -8
  167. package/build/server/chunks/{_page.svelte-aT9hOnbL.js.map → _page.svelte-DFzKfImt.js.map} +1 -1
  168. package/build/server/chunks/{_page.svelte-D5-pMskg.js → _page.svelte-ZYW4iSHn.js} +8 -8
  169. package/build/server/chunks/{_page.svelte-D5-pMskg.js.map → _page.svelte-ZYW4iSHn.js.map} +1 -1
  170. package/build/server/chunks/{index2-eSFyMQpS.js → index2-DBFlGzWV.js} +2 -2
  171. package/build/server/chunks/{index2-eSFyMQpS.js.map → index2-DBFlGzWV.js.map} +1 -1
  172. package/build/server/chunks/{mongo-BHk5yAj9.js → mongo-Ndoh6fs5.js} +21 -7
  173. package/build/server/chunks/mongo-Ndoh6fs5.js.map +1 -0
  174. package/build/server/chunks/{remote-xxtqbu-ETLGkdRu.js → remote-xxtqbu-fbBqzvFu.js} +3 -3
  175. package/build/server/chunks/remote-xxtqbu-fbBqzvFu.js.map +1 -0
  176. package/build/server/chunks/{servers.remote-CGies_Na.js → servers.remote-B1eorl4A.js} +163 -12
  177. package/build/server/chunks/servers.remote-B1eorl4A.js.map +1 -0
  178. package/build/server/index.js +2 -2
  179. package/build/server/index.js.map +1 -1
  180. package/build/server/manifest.js +15 -15
  181. package/build/server/manifest.js.map +1 -1
  182. package/package.json +1 -1
  183. package/src/api/servers.remote.ts +196 -10
  184. package/src/app.css +3 -6
  185. package/src/lib/components/ExplainPanel.svelte +273 -0
  186. package/src/lib/components/JsonValue.svelte +51 -6
  187. package/src/lib/components/Modal.svelte +7 -2
  188. package/src/lib/components/Notifications.svelte +3 -15
  189. package/src/lib/components/PrettyJson.svelte +1 -1
  190. package/src/lib/components/SearchBox.svelte +160 -5
  191. package/src/lib/components/TimeRangeStats.svelte +269 -0
  192. package/src/lib/icons/IconClose.svelte +21 -0
  193. package/src/lib/icons/IconExternalLink.svelte +22 -0
  194. package/src/lib/server/mongo.ts +31 -6
  195. package/src/lib/types.ts +16 -5
  196. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/+page.svelte +49 -1
  197. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/mappings/+page.svelte +219 -79
  198. package/build/client/_app/immutable/assets/0.CEIWAdGZ.css +0 -1
  199. package/build/client/_app/immutable/assets/0.CEIWAdGZ.css.br +0 -0
  200. package/build/client/_app/immutable/assets/0.CEIWAdGZ.css.gz +0 -0
  201. package/build/client/_app/immutable/assets/10.BrydhPds.css +0 -1
  202. package/build/client/_app/immutable/assets/10.BrydhPds.css.br +0 -0
  203. package/build/client/_app/immutable/assets/10.BrydhPds.css.gz +0 -0
  204. package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css.br +0 -0
  205. package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css.gz +0 -0
  206. package/build/client/_app/immutable/chunks/0oUK0vJa.js +0 -1
  207. package/build/client/_app/immutable/chunks/0oUK0vJa.js.br +0 -0
  208. package/build/client/_app/immutable/chunks/0oUK0vJa.js.gz +0 -0
  209. package/build/client/_app/immutable/chunks/BGXqurs_.js +0 -1
  210. package/build/client/_app/immutable/chunks/BGXqurs_.js.br +0 -0
  211. package/build/client/_app/immutable/chunks/BGXqurs_.js.gz +0 -0
  212. package/build/client/_app/immutable/chunks/BO6_ugNx.js.br +0 -0
  213. package/build/client/_app/immutable/chunks/BO6_ugNx.js.gz +0 -0
  214. package/build/client/_app/immutable/chunks/BPbCnJEo.js +0 -1
  215. package/build/client/_app/immutable/chunks/BPbCnJEo.js.br +0 -0
  216. package/build/client/_app/immutable/chunks/BPbCnJEo.js.gz +0 -0
  217. package/build/client/_app/immutable/chunks/BXUq66wC.js.br +0 -0
  218. package/build/client/_app/immutable/chunks/BXUq66wC.js.gz +0 -0
  219. package/build/client/_app/immutable/chunks/BxoAxRg6.js +0 -1
  220. package/build/client/_app/immutable/chunks/BxoAxRg6.js.br +0 -0
  221. package/build/client/_app/immutable/chunks/BxoAxRg6.js.gz +0 -0
  222. package/build/client/_app/immutable/chunks/ByCRZ7zS.js +0 -2
  223. package/build/client/_app/immutable/chunks/ByCRZ7zS.js.br +0 -0
  224. package/build/client/_app/immutable/chunks/ByCRZ7zS.js.gz +0 -0
  225. package/build/client/_app/immutable/chunks/BziC6PX1.js.br +0 -0
  226. package/build/client/_app/immutable/chunks/BziC6PX1.js.gz +0 -0
  227. package/build/client/_app/immutable/chunks/CpnIKQd1.js.br +0 -0
  228. package/build/client/_app/immutable/chunks/CpnIKQd1.js.gz +0 -0
  229. package/build/client/_app/immutable/chunks/DIw4Wyr4.js.br +0 -0
  230. package/build/client/_app/immutable/chunks/DIw4Wyr4.js.gz +0 -0
  231. package/build/client/_app/immutable/chunks/DkI4PMxL.js.br +0 -0
  232. package/build/client/_app/immutable/chunks/DkI4PMxL.js.gz +0 -0
  233. package/build/client/_app/immutable/chunks/Dkr5ZtQR.js.br +0 -0
  234. package/build/client/_app/immutable/chunks/Dkr5ZtQR.js.gz +0 -0
  235. package/build/client/_app/immutable/chunks/DmXOK2q9.js +0 -16
  236. package/build/client/_app/immutable/chunks/DmXOK2q9.js.br +0 -0
  237. package/build/client/_app/immutable/chunks/DmXOK2q9.js.gz +0 -0
  238. package/build/client/_app/immutable/chunks/Dn0_-jEe.js.br +0 -0
  239. package/build/client/_app/immutable/chunks/Dn0_-jEe.js.gz +0 -0
  240. package/build/client/_app/immutable/chunks/UJuWD2W4.js.br +0 -0
  241. package/build/client/_app/immutable/chunks/UJuWD2W4.js.gz +0 -0
  242. package/build/client/_app/immutable/chunks/Z2a-si5C.js.br +0 -0
  243. package/build/client/_app/immutable/chunks/Z2a-si5C.js.gz +0 -0
  244. package/build/client/_app/immutable/chunks/_kKBJjiB.js +0 -1
  245. package/build/client/_app/immutable/chunks/_kKBJjiB.js.br +0 -0
  246. package/build/client/_app/immutable/chunks/_kKBJjiB.js.gz +0 -0
  247. package/build/client/_app/immutable/chunks/reNJcONQ.js.br +0 -0
  248. package/build/client/_app/immutable/chunks/s-K2chw6.js +0 -1
  249. package/build/client/_app/immutable/chunks/s-K2chw6.js.br +0 -0
  250. package/build/client/_app/immutable/chunks/s-K2chw6.js.gz +0 -0
  251. package/build/client/_app/immutable/entry/app.BBGxwcK8.js +0 -2
  252. package/build/client/_app/immutable/entry/app.BBGxwcK8.js.br +0 -0
  253. package/build/client/_app/immutable/entry/app.BBGxwcK8.js.gz +0 -0
  254. package/build/client/_app/immutable/entry/start.Cu5iaSNG.js +0 -1
  255. package/build/client/_app/immutable/entry/start.Cu5iaSNG.js.br +0 -0
  256. package/build/client/_app/immutable/entry/start.Cu5iaSNG.js.gz +0 -0
  257. package/build/client/_app/immutable/nodes/0.OznVrT12.js +0 -1
  258. package/build/client/_app/immutable/nodes/0.OznVrT12.js.br +0 -0
  259. package/build/client/_app/immutable/nodes/0.OznVrT12.js.gz +0 -0
  260. package/build/client/_app/immutable/nodes/1.BnbJyDlh.js +0 -1
  261. package/build/client/_app/immutable/nodes/1.BnbJyDlh.js.br +0 -2
  262. package/build/client/_app/immutable/nodes/1.BnbJyDlh.js.gz +0 -0
  263. package/build/client/_app/immutable/nodes/10.4wMOwZtW.js +0 -3
  264. package/build/client/_app/immutable/nodes/10.4wMOwZtW.js.br +0 -0
  265. package/build/client/_app/immutable/nodes/10.4wMOwZtW.js.gz +0 -0
  266. package/build/client/_app/immutable/nodes/11.IKyzjYy6.js.br +0 -0
  267. package/build/client/_app/immutable/nodes/11.IKyzjYy6.js.gz +0 -0
  268. package/build/client/_app/immutable/nodes/12.BYM9mUpP.js +0 -1
  269. package/build/client/_app/immutable/nodes/12.BYM9mUpP.js.br +0 -0
  270. package/build/client/_app/immutable/nodes/12.BYM9mUpP.js.gz +0 -0
  271. package/build/client/_app/immutable/nodes/13.ndMcrfHr.js +0 -66
  272. package/build/client/_app/immutable/nodes/13.ndMcrfHr.js.br +0 -0
  273. package/build/client/_app/immutable/nodes/13.ndMcrfHr.js.gz +0 -0
  274. package/build/client/_app/immutable/nodes/2.DqvBb3C7.js.br +0 -0
  275. package/build/client/_app/immutable/nodes/2.DqvBb3C7.js.gz +0 -0
  276. package/build/client/_app/immutable/nodes/3.27swwcG4.js.br +0 -0
  277. package/build/client/_app/immutable/nodes/3.27swwcG4.js.gz +0 -0
  278. package/build/client/_app/immutable/nodes/4.CcholrFe.js.br +0 -0
  279. package/build/client/_app/immutable/nodes/4.CcholrFe.js.gz +0 -0
  280. package/build/client/_app/immutable/nodes/5.CzudN9q-.js.br +0 -0
  281. package/build/client/_app/immutable/nodes/5.CzudN9q-.js.gz +0 -0
  282. package/build/client/_app/immutable/nodes/7.C560Uxhw.js.br +0 -0
  283. package/build/client/_app/immutable/nodes/7.C560Uxhw.js.gz +0 -0
  284. package/build/client/_app/immutable/nodes/8.BEOgol-D.js.br +0 -0
  285. package/build/client/_app/immutable/nodes/8.BEOgol-D.js.gz +0 -0
  286. package/build/client/_app/immutable/nodes/9.BmG9LqpS.js.br +0 -0
  287. package/build/client/_app/immutable/nodes/9.BmG9LqpS.js.gz +0 -0
  288. package/build/server/chunks/0-DgHP79Ti.js +0 -22
  289. package/build/server/chunks/1--T1OTbjT.js +0 -9
  290. package/build/server/chunks/10-D1OhJt-m.js.map +0 -1
  291. package/build/server/chunks/JsonValue-Cexm3jGT.js.map +0 -1
  292. package/build/server/chunks/Modal-BzZ9u6V6.js.map +0 -1
  293. package/build/server/chunks/PrettyJson-tOt0PqjF.js.map +0 -1
  294. package/build/server/chunks/_layout.svelte-Dji2JJ9X.js.map +0 -1
  295. package/build/server/chunks/_page.svelte-CJ5HzoD0.js +0 -203
  296. package/build/server/chunks/_page.svelte-CJ5HzoD0.js.map +0 -1
  297. package/build/server/chunks/_page.svelte-D-23v2Aa.js.map +0 -1
  298. package/build/server/chunks/mongo-BHk5yAj9.js.map +0 -1
  299. package/build/server/chunks/remote-xxtqbu-ETLGkdRu.js.map +0 -1
  300. 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 hasMappings}
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
- <svg
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: #32d74b;
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 { params = $bindable(), editMode = $bindable(false), readonly = $bindable(false) }: Props = $props();
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
- <button
190
- type="submit"
191
- class="h-9 px-4 rounded-xl bg-[var(--button-success)] text-white font-semibold transition cursor-pointer hover:bg-[var(--button-success-l)] active:brightness-95"
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>