@medusajs/dashboard 3.0.0-snapshot-20251214110905 → 3.0.0-snapshot-20251215162333

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 (197) hide show
  1. package/dist/{adjust-inventory-I5VYMAI4.mjs → adjust-inventory-26YXAXQL.mjs} +2 -1
  2. package/dist/{api-key-management-create-CVRFY4PL.mjs → api-key-management-create-EMP32G2D.mjs} +4 -3
  3. package/dist/{api-key-management-detail-HRVP6HRC.mjs → api-key-management-detail-NRGL7HHX.mjs} +11 -10
  4. package/dist/{api-key-management-edit-JMU3WEPX.mjs → api-key-management-edit-IBM3ZXHK.mjs} +4 -3
  5. package/dist/{api-key-management-list-RGLZMUCB.mjs → api-key-management-list-LJSWRAGE.mjs} +4 -3
  6. package/dist/{api-key-management-sales-channels-4OU5VGIG.mjs → api-key-management-sales-channels-3GRNDBZ4.mjs} +4 -3
  7. package/dist/app.css +3 -0
  8. package/dist/app.js +1085 -835
  9. package/dist/app.mjs +12 -11
  10. package/dist/{campaign-detail-BDI3P2SF.mjs → campaign-detail-22Q6XWGL.mjs} +11 -10
  11. package/dist/{categories-metadata-BARTITD5.mjs → categories-metadata-J7M3XWI7.mjs} +11 -10
  12. package/dist/{category-create-L2KJCHPO.mjs → category-create-KHJZSC7G.mjs} +3 -2
  13. package/dist/{category-detail-CUMEBNXU.mjs → category-detail-RRKJPMEG.mjs} +13 -12
  14. package/dist/{category-edit-U6SLZSAX.mjs → category-edit-CTA2EPDG.mjs} +3 -2
  15. package/dist/{category-list-W7JW4PWA.mjs → category-list-4HZP4FRE.mjs} +4 -3
  16. package/dist/{category-organize-LLSVAO3U.mjs → category-organize-SXP33XET.mjs} +3 -2
  17. package/dist/{category-products-GYXTDDBQ.mjs → category-products-EFZRTCSF.mjs} +12 -11
  18. package/dist/{chunk-XIVBRONM.mjs → chunk-23GTCEOV.mjs} +1 -1
  19. package/dist/{chunk-N3FCYZV6.mjs → chunk-2XTBDCGE.mjs} +1 -1
  20. package/dist/{chunk-DS5IRNJY.mjs → chunk-32FPYJ3S.mjs} +1 -1
  21. package/dist/{chunk-FPBKWWSI.mjs → chunk-43X7ZR3P.mjs} +1 -1
  22. package/dist/{chunk-RU4ZS47V.mjs → chunk-4JQR6QNW.mjs} +2 -2
  23. package/dist/{chunk-Z6NHG5LQ.mjs → chunk-6P4Q4AAP.mjs} +3 -3
  24. package/dist/{chunk-F5NZDW7L.mjs → chunk-A2WBKOXJ.mjs} +2 -2
  25. package/dist/{chunk-F63F3FIT.mjs → chunk-A4XYK3MY.mjs} +2 -2
  26. package/dist/{chunk-NT6C7CHT.mjs → chunk-AWRCV3ME.mjs} +1 -1
  27. package/dist/{chunk-5X6SKB2P.mjs → chunk-BMS2QLJY.mjs} +1 -1
  28. package/dist/{chunk-67KHYLIQ.mjs → chunk-DK7IWUMK.mjs} +3 -3
  29. package/dist/{chunk-FEB3ZGTL.mjs → chunk-DNUVCBN7.mjs} +159 -5
  30. package/dist/{chunk-N4O5FAUC.mjs → chunk-FYWHE3W5.mjs} +1 -1
  31. package/dist/{chunk-HKKZJTRO.mjs → chunk-GRZSG4EP.mjs} +89 -34
  32. package/dist/chunk-HGRIOEAR.mjs +32 -0
  33. package/dist/{chunk-Y5UO73CH.mjs → chunk-HTCYX4VD.mjs} +1 -1
  34. package/dist/{chunk-34KFHPN6.mjs → chunk-IAV7IKJ6.mjs} +1 -1
  35. package/dist/{chunk-3BJLNORD.mjs → chunk-KQ4LC2YV.mjs} +1 -1
  36. package/dist/{chunk-GC3QXC6D.mjs → chunk-OHY2N2Q4.mjs} +4 -4
  37. package/dist/{chunk-7AX6R6G6.mjs → chunk-OSHH5GAS.mjs} +13 -1
  38. package/dist/{chunk-PXZEQZ6Q.mjs → chunk-PHLCT2HA.mjs} +1 -1
  39. package/dist/{chunk-35LSPN2U.mjs → chunk-QKALAT7P.mjs} +1 -1
  40. package/dist/{chunk-BBTE6VKD.mjs → chunk-RL5EYTP6.mjs} +1 -1
  41. package/dist/{chunk-B3AOQW2B.mjs → chunk-U6G4M5LP.mjs} +1 -1
  42. package/dist/{chunk-HKIF5HVL.mjs → chunk-UJ2TMPV4.mjs} +12 -0
  43. package/dist/{chunk-NHDFPGQ3.mjs → chunk-UWY5ZV66.mjs} +13 -1
  44. package/dist/{chunk-AH4DORIW.mjs → chunk-XY7A7GZJ.mjs} +1 -1
  45. package/dist/{chunk-FQDPOKEK.mjs → chunk-Y2YVTIJI.mjs} +1 -1
  46. package/dist/{chunk-Q4AXBDFH.mjs → chunk-YTYDWNYA.mjs} +155 -153
  47. package/dist/{chunk-2HDKZN4Q.mjs → chunk-YYOPBKME.mjs} +3 -3
  48. package/dist/{chunk-LEJUZW3P.mjs → chunk-Z6BFNHEO.mjs} +12 -0
  49. package/dist/{chunk-AIZ6W4QI.mjs → chunk-ZMG5B4FG.mjs} +1 -1
  50. package/dist/{collection-add-products-4WBPS6PY.mjs → collection-add-products-XUMV6XR7.mjs} +12 -11
  51. package/dist/{collection-create-4JX4YE47.mjs → collection-create-GWKWVT7B.mjs} +3 -2
  52. package/dist/{collection-detail-HT4SSV32.mjs → collection-detail-ONRBKJLN.mjs} +12 -11
  53. package/dist/{collection-edit-MXL35GQQ.mjs → collection-edit-EZIO2BR5.mjs} +3 -2
  54. package/dist/{collection-list-FYONEBDN.mjs → collection-list-XCC4SIPJ.mjs} +13 -12
  55. package/dist/{collection-metadata-YEZ2TBRX.mjs → collection-metadata-QK7MI3D2.mjs} +11 -10
  56. package/dist/{customer-detail-MB7CS7OG.mjs → customer-detail-FR6J37ZC.mjs} +12 -11
  57. package/dist/{customer-group-detail-U5UAP7QS.mjs → customer-group-detail-YSKSNETG.mjs} +11 -10
  58. package/dist/{customer-group-list-KAS6JSCQ.mjs → customer-group-list-XBCD4FZH.mjs} +11 -10
  59. package/dist/{customers-add-customer-group-UKLSPYEU.mjs → customers-add-customer-group-Q7FMR2Y5.mjs} +11 -10
  60. package/dist/{edit-inventory-item-RATTNP2Y.mjs → edit-inventory-item-H7DAZWIT.mjs} +2 -1
  61. package/dist/{edit-inventory-item-attributes-JHH5GSNL.mjs → edit-inventory-item-attributes-7HTXXPGZ.mjs} +2 -1
  62. package/dist/{edit-reservation-UZCSNLHY.mjs → edit-reservation-OVTRZHJR.mjs} +3 -2
  63. package/dist/{edit-rules-VMEHCXYQ.mjs → edit-rules-SMVRTCUP.mjs} +11 -10
  64. package/dist/en.json +1 -0
  65. package/dist/{inventory-create-KN72V2KK.mjs → inventory-create-3XONKYMZ.mjs} +12 -11
  66. package/dist/{inventory-detail-7OHCFAJO.mjs → inventory-detail-6A6GOLB6.mjs} +11 -10
  67. package/dist/{inventory-list-BQPHK3FV.mjs → inventory-list-2CJLAK3X.mjs} +2 -1
  68. package/dist/{inventory-metadata-I3IRRMLH.mjs → inventory-metadata-FNEJ3RAT.mjs} +11 -10
  69. package/dist/{inventory-stock-5IUICNEH.mjs → inventory-stock-S3ZYYCMZ.mjs} +13 -12
  70. package/dist/{location-detail-3MSUGB4W.mjs → location-detail-N3GUZSY7.mjs} +11 -10
  71. package/dist/{location-fulfillment-providers-ZVZMLCIC.mjs → location-fulfillment-providers-WM6DT252.mjs} +13 -12
  72. package/dist/{location-sales-channels-NKNM5TQK.mjs → location-sales-channels-WLVTMU4Z.mjs} +3 -2
  73. package/dist/{location-service-zone-shipping-option-create-CZWEHKVJ.mjs → location-service-zone-shipping-option-create-MJPH3WKX.mjs} +13 -12
  74. package/dist/{location-service-zone-shipping-option-pricing-Z5IFOLFJ.mjs → location-service-zone-shipping-option-pricing-6IRNPWJY.mjs} +2 -2
  75. package/dist/{login-OCYZM7SI.mjs → login-VNOLI5YG.mjs} +11 -10
  76. package/dist/{manage-locations-MLNMPQ5I.mjs → manage-locations-7HH6R4UP.mjs} +2 -1
  77. package/dist/{order-allocate-items-VRPPVPP3.mjs → order-allocate-items-HZGGYJ42.mjs} +4 -3
  78. package/dist/{order-create-claim-O3ZYTAIC.mjs → order-create-claim-GUYTLVPB.mjs} +13 -12
  79. package/dist/{order-create-edit-HUS7IRS3.mjs → order-create-edit-ODIN6GRW.mjs} +12 -11
  80. package/dist/{order-create-exchange-TUP4NHHX.mjs → order-create-exchange-ZT5RBRKL.mjs} +13 -12
  81. package/dist/{order-create-fulfillment-4BGDYHBB.mjs → order-create-fulfillment-OWUVTZXW.mjs} +11 -10
  82. package/dist/{order-create-refund-FA5ERI7M.mjs → order-create-refund-Q6HQY42R.mjs} +11 -10
  83. package/dist/{order-create-return-7GPHJ2WU.mjs → order-create-return-E2KILJX2.mjs} +5 -4
  84. package/dist/{order-create-shipment-27UBYPKT.mjs → order-create-shipment-WAGGEPRW.mjs} +11 -10
  85. package/dist/{order-detail-2J7KDTKG.mjs → order-detail-HFJONELJ.mjs} +15 -14
  86. package/dist/{order-edit-billing-address-E7CD5FBQ.mjs → order-edit-billing-address-UM76J4KX.mjs} +11 -10
  87. package/dist/{order-edit-email-ELRIQYVN.mjs → order-edit-email-CL3KNOCM.mjs} +11 -10
  88. package/dist/{order-edit-shipping-address-HVNAJUZI.mjs → order-edit-shipping-address-PIESTGVL.mjs} +11 -10
  89. package/dist/{order-export-TRMFVBFO.mjs → order-export-4MZUPMGD.mjs} +12 -11
  90. package/dist/{order-list-Y4FET3XV.mjs → order-list-ACSFGIPD.mjs} +6 -5
  91. package/dist/{order-metadata-THARHEJC.mjs → order-metadata-FHBB7MTG.mjs} +11 -10
  92. package/dist/{order-receive-return-X5ASB7DL.mjs → order-receive-return-PRVKP6J2.mjs} +12 -11
  93. package/dist/{order-request-transfer-PKF4ULJY.mjs → order-request-transfer-XSAGRUMT.mjs} +11 -10
  94. package/dist/{price-list-configuration-SZRY7CXO.mjs → price-list-configuration-IHPSUNZJ.mjs} +3 -2
  95. package/dist/{price-list-create-TYNSJDDM.mjs → price-list-create-YHXRQSC3.mjs} +14 -13
  96. package/dist/{price-list-detail-ORYFRNB6.mjs → price-list-detail-FR3FQR3H.mjs} +13 -12
  97. package/dist/{price-list-edit-I5QNCWJP.mjs → price-list-edit-53UW35L3.mjs} +3 -2
  98. package/dist/{price-list-list-AZOGEZAS.mjs → price-list-list-YSEM6IAI.mjs} +4 -3
  99. package/dist/{price-list-prices-add-MWAUNUBF.mjs → price-list-prices-add-GJVI47OY.mjs} +14 -13
  100. package/dist/{price-list-prices-edit-Z4YJ4YBY.mjs → price-list-prices-edit-E4Q5TQPM.mjs} +5 -4
  101. package/dist/{product-attributes-5QW6ZEYB.mjs → product-attributes-TKCE2M63.mjs} +12 -11
  102. package/dist/{product-create-YQ76CEF3.mjs → product-create-OLDZPMLW.mjs} +14 -13
  103. package/dist/{product-create-option-UMZKRNTC.mjs → product-create-option-7AOXAA4S.mjs} +2 -1
  104. package/dist/{product-create-variant-IASRY2JX.mjs → product-create-variant-KEBN5OR7.mjs} +12 -11
  105. package/dist/{product-detail-NVLJQGGK.mjs → product-detail-O6QWJIKR.mjs} +12 -11
  106. package/dist/{product-edit-DP42G3EU.mjs → product-edit-56XDGDUN.mjs} +12 -11
  107. package/dist/{product-edit-option-ZMTSLRG5.mjs → product-edit-option-LWJT3CYJ.mjs} +2 -1
  108. package/dist/{product-export-OK5FCD42.mjs → product-export-WUZYHPS5.mjs} +13 -12
  109. package/dist/{product-image-variants-edit-VEWNL52X.mjs → product-image-variants-edit-Y363J5NG.mjs} +11 -10
  110. package/dist/{product-import-LX625CIX.mjs → product-import-V3KQN4TV.mjs} +11 -10
  111. package/dist/{product-list-TXEPE6NL.mjs → product-list-DNTS7WUN.mjs} +12 -11
  112. package/dist/{product-media-ULNJ7JJY.mjs → product-media-3VJ7KENL.mjs} +2 -1
  113. package/dist/{product-metadata-ZKKBE6GG.mjs → product-metadata-GL2MVPDI.mjs} +11 -10
  114. package/dist/{product-organization-NMA2WJNT.mjs → product-organization-PNKWRNHC.mjs} +13 -12
  115. package/dist/{product-prices-5WCCQDS6.mjs → product-prices-JOG6IIQ7.mjs} +3 -2
  116. package/dist/{product-sales-channels-2PN4L7II.mjs → product-sales-channels-ANCFZZ5S.mjs} +3 -2
  117. package/dist/{product-shipping-profile-45XXB7FM.mjs → product-shipping-profile-ETQFZ7DC.mjs} +2 -1
  118. package/dist/{product-stock-KUHH6MFA.mjs → product-stock-NYUFMEVG.mjs} +13 -12
  119. package/dist/{product-tag-create-7EVRE5BL.mjs → product-tag-create-PQMDDKWH.mjs} +11 -10
  120. package/dist/{product-tag-detail-WULO55NT.mjs → product-tag-detail-EHBB3WUB.mjs} +14 -13
  121. package/dist/{product-tag-edit-J4ODRLXN.mjs → product-tag-edit-K3BBQLJR.mjs} +11 -10
  122. package/dist/{product-tag-list-V4CCQTL6.mjs → product-tag-list-LSW5FFVN.mjs} +14 -13
  123. package/dist/{product-tag-metadata-KHDYQMSG.mjs → product-tag-metadata-MJH5LH7E.mjs} +11 -10
  124. package/dist/{product-type-create-KHSNCQCV.mjs → product-type-create-DRFXTL5O.mjs} +2 -1
  125. package/dist/{product-type-detail-F35MUSLD.mjs → product-type-detail-3VB6AWUW.mjs} +13 -12
  126. package/dist/{product-type-edit-3LRBWZ3S.mjs → product-type-edit-SRHCZDK7.mjs} +2 -1
  127. package/dist/{product-type-list-K2GULUPF.mjs → product-type-list-FD3TGPNP.mjs} +3 -2
  128. package/dist/{product-type-metadata-CGXFFEJO.mjs → product-type-metadata-CDJDFFGQ.mjs} +11 -10
  129. package/dist/{product-variant-detail-NT2MB3Z4.mjs → product-variant-detail-43T33AQP.mjs} +11 -10
  130. package/dist/{product-variant-edit-KZ6D5CSA.mjs → product-variant-edit-DEZEY2H2.mjs} +11 -10
  131. package/dist/{product-variant-manage-inventory-items-OGM64KYP.mjs → product-variant-manage-inventory-items-Y2VEOHP7.mjs} +2 -1
  132. package/dist/{product-variant-media-C3KCFODU.mjs → product-variant-media-2WLVNGI4.mjs} +2 -1
  133. package/dist/{product-variant-metadata-I2PN64TH.mjs → product-variant-metadata-VTZDNWUT.mjs} +11 -10
  134. package/dist/{promotion-create-4KVSXYAI.mjs → promotion-create-HWFNUQXG.mjs} +11 -10
  135. package/dist/{promotion-detail-NGNVELME.mjs → promotion-detail-VJB55PJK.mjs} +11 -10
  136. package/dist/{refund-reason-create-CTAPBK3X.mjs → refund-reason-create-YHCDEHGQ.mjs} +11 -10
  137. package/dist/{refund-reason-edit-B6HRNXGE.mjs → refund-reason-edit-CZ5QZ2SZ.mjs} +11 -10
  138. package/dist/{refund-reason-list-7OUHUORB.mjs → refund-reason-list-URYYYEK6.mjs} +11 -10
  139. package/dist/{region-metadata-GRG3QSJY.mjs → region-metadata-H6XXUQ4S.mjs} +11 -10
  140. package/dist/{reservation-create-C6HTEF3R.mjs → reservation-create-ZCIYM6JI.mjs} +3 -2
  141. package/dist/{reservation-detail-KAI7N5UP.mjs → reservation-detail-LZAQL4XA.mjs} +11 -10
  142. package/dist/{reservation-list-SOJRN5RI.mjs → reservation-list-2DN3YHIJ.mjs} +3 -2
  143. package/dist/{reservation-metadata-TWV7KLOB.mjs → reservation-metadata-5HZSDDOK.mjs} +11 -10
  144. package/dist/{sales-channel-add-products-CBECZU46.mjs → sales-channel-add-products-VH5T3GDA.mjs} +12 -11
  145. package/dist/{sales-channel-create-4XLJDVJO.mjs → sales-channel-create-MI7HHZYE.mjs} +3 -2
  146. package/dist/{sales-channel-detail-NQSBPPIE.mjs → sales-channel-detail-I2ZHVXMG.mjs} +12 -11
  147. package/dist/{sales-channel-edit-UZGSXD5X.mjs → sales-channel-edit-VSHOIR37.mjs} +3 -2
  148. package/dist/{sales-channel-list-UYN2OCBR.mjs → sales-channel-list-3FV4S2NN.mjs} +11 -10
  149. package/dist/{sales-channel-metadata-4XWXYN2E.mjs → sales-channel-metadata-M364R4RJ.mjs} +11 -10
  150. package/dist/{shipping-option-type-create-U7PIKVMV.mjs → shipping-option-type-create-C5WUWON7.mjs} +11 -10
  151. package/dist/{shipping-option-type-detail-QNZLQGI6.mjs → shipping-option-type-detail-PENS2K73.mjs} +12 -11
  152. package/dist/{shipping-option-type-edit-BP6HLZ7B.mjs → shipping-option-type-edit-CIU5EHRP.mjs} +11 -10
  153. package/dist/{shipping-option-type-list-L274RM6A.mjs → shipping-option-type-list-ZMZMXFME.mjs} +12 -11
  154. package/dist/{shipping-profile-metadata-BZKPLXHO.mjs → shipping-profile-metadata-75G2NNMA.mjs} +11 -10
  155. package/dist/{store-add-locales-EXR3NLOM.mjs → store-add-locales-IZOZP5C6.mjs} +12 -18
  156. package/dist/{store-detail-T4YY5NHG.mjs → store-detail-4IBAEVSD.mjs} +16 -28
  157. package/dist/{store-edit-AB5CDUTK.mjs → store-edit-5ZS562ZO.mjs} +1 -42
  158. package/dist/{store-metadata-FN3WZLXA.mjs → store-metadata-CYXTVJUE.mjs} +11 -10
  159. package/dist/{tax-region-create-PWXTFE3Q.mjs → tax-region-create-DWGL4EUT.mjs} +11 -10
  160. package/dist/{tax-region-detail-GJW63AMV.mjs → tax-region-detail-O2T7BI3V.mjs} +16 -15
  161. package/dist/{tax-region-edit-WOUO7TPQ.mjs → tax-region-edit-EEVEEU2Q.mjs} +11 -10
  162. package/dist/{tax-region-province-detail-FCHPIRXW.mjs → tax-region-province-detail-2W7RXAM5.mjs} +16 -15
  163. package/dist/{tax-region-tax-override-create-ZLWXRNLN.mjs → tax-region-tax-override-create-7IM4ZVPH.mjs} +14 -13
  164. package/dist/{tax-region-tax-override-edit-ZM2JUFNJ.mjs → tax-region-tax-override-edit-3ZT5IZYR.mjs} +15 -14
  165. package/dist/{translation-list-Y2GWTRGW.mjs → translation-list-AFK5MGSH.mjs} +68 -79
  166. package/dist/{translations-edit-PM4PSMRF.mjs → translations-edit-EN47PWTO.mjs} +146 -81
  167. package/dist/{user-detail-KEDJ7N3Q.mjs → user-detail-BJUXLZZQ.mjs} +2 -1
  168. package/dist/{user-metadata-LNADHFTW.mjs → user-metadata-2WPJOEJA.mjs} +11 -10
  169. package/dist/{workflow-execution-detail-POTSURJX.mjs → workflow-execution-detail-H2AKEZJX.mjs} +11 -10
  170. package/package.json +9 -9
  171. package/src/components/data-grid/components/data-grid-root.tsx +184 -5
  172. package/src/components/data-grid/data-grid.tsx +12 -1
  173. package/src/components/data-grid/helpers/create-data-grid-column-helper.ts +18 -0
  174. package/src/components/data-grid/hooks/use-data-grid-cell.tsx +1 -1
  175. package/src/hooks/api/categories.tsx +32 -0
  176. package/src/hooks/api/collections.tsx +31 -0
  177. package/src/hooks/api/product-types.tsx +32 -0
  178. package/src/hooks/api/product-variants.tsx +40 -2
  179. package/src/hooks/api/products.tsx +29 -0
  180. package/src/hooks/api/tags.tsx +32 -0
  181. package/src/hooks/api/translations.tsx +114 -62
  182. package/src/hooks/use-infinite-list.tsx +92 -0
  183. package/src/i18n/translations/$schema.json +4 -0
  184. package/src/i18n/translations/en.json +1 -0
  185. package/src/i18n/translations/es.json +1 -0
  186. package/src/routes/store/store-add-locales/components/add-locales-form/add-locales-form.tsx +0 -9
  187. package/src/routes/store/store-detail/components/store-general-section/store-general-section.tsx +0 -24
  188. package/src/routes/store/store-detail/components/store-locale-section/store-locale-section.tsx +1 -9
  189. package/src/routes/store/store-edit/components/edit-store-form/edit-store-form.tsx +1 -45
  190. package/src/routes/translations/translation-list/components/active-locales-section/active-locales-section.tsx +2 -2
  191. package/src/routes/translations/translation-list/components/translation-list-section/translation-list-section.tsx +1 -8
  192. package/src/routes/translations/translation-list/components/translations-completion-section/translations-completion-section.tsx +10 -4
  193. package/src/routes/translations/translation-list/translation-list.tsx +66 -68
  194. package/src/routes/translations/translations-edit/components/translations-edit-form/translations-edit-form.tsx +131 -65
  195. package/src/routes/translations/translations-edit/translations-edit.tsx +36 -12
  196. package/src/routes/translations/translations-edit/utils/index.ts +0 -1
  197. package/src/routes/translations/translations-edit/utils/reference-label-map.ts +0 -10
@@ -1,16 +1,22 @@
1
+ import { AdminTranslationEntityStatistics } from "@medusajs/types"
1
2
  import { Container, Heading, Text } from "@medusajs/ui"
2
3
  import { useTranslation } from "react-i18next"
3
4
 
4
5
  type TranslationsCompletionSectionProps = {
5
- translatedCount?: number
6
- totalCount?: number
6
+ statistics: Record<string, AdminTranslationEntityStatistics>
7
7
  }
8
8
 
9
9
  export const TranslationsCompletionSection = ({
10
- translatedCount = 0,
11
- totalCount = 0,
10
+ statistics,
12
11
  }: TranslationsCompletionSectionProps) => {
13
12
  const { t } = useTranslation()
13
+ const { translatedCount, totalCount } = Object.values(statistics).reduce(
14
+ (acc, curr) => ({
15
+ translatedCount: acc.translatedCount + curr.translated,
16
+ totalCount: acc.totalCount + curr.expected,
17
+ }),
18
+ { totalCount: 0, translatedCount: 0 }
19
+ )
14
20
 
15
21
  const percentage = totalCount > 0 ? (translatedCount / totalCount) * 100 : 0
16
22
  const remaining = Math.max(0, totalCount - translatedCount)
@@ -2,96 +2,92 @@ import { Container, Heading, Text } from "@medusajs/ui"
2
2
  import { TwoColumnPage } from "../../../components/layout/pages"
3
3
  import { useTranslation } from "react-i18next"
4
4
  import { Buildings } from "@medusajs/icons"
5
- import { useStore } from "../../../hooks/api"
5
+ import {
6
+ useStore,
7
+ useTranslationSettings,
8
+ useTranslationStatistics,
9
+ } from "../../../hooks/api"
6
10
  import { ActiveLocalesSection } from "./components/active-locales-section/active-locales-section"
7
11
  import { TranslationListSection } from "./components/translation-list-section/translation-list-section"
8
12
  import { TranslationsCompletionSection } from "./components/translations-completion-section/translations-completion-section"
9
13
  import { TwoColumnPageSkeleton } from "../../../components/common/skeleton"
14
+ import { useMemo } from "react"
10
15
 
11
16
  export type TranslatableEntity = {
12
- icon: React.ReactNode
13
17
  label: string
14
18
  reference: string
19
+ translatableFields: string[]
15
20
  translatedCount?: number
16
21
  totalCount?: number
17
22
  }
18
23
 
19
- const TRANSLATABLE_ENTITIES: TranslatableEntity[] = [
20
- {
21
- icon: <Buildings />,
22
- label: "Product",
23
- reference: "product",
24
- translatedCount: 4,
25
- totalCount: 96,
26
- },
27
- {
28
- icon: <Buildings />,
29
- label: "Product Variants",
30
- reference: "product_variant",
31
- translatedCount: 4,
32
- totalCount: 200000,
33
- },
34
- {
35
- icon: <Buildings />,
36
- label: "Product Categories",
37
- reference: "product_category",
38
- translatedCount: 96,
39
- totalCount: 96,
40
- },
41
- {
42
- icon: <Buildings />,
43
- label: "Product Collections",
44
- reference: "product_collection",
45
- translatedCount: 4,
46
- totalCount: 96,
47
- },
48
- {
49
- icon: <Buildings />,
50
- label: "Product Types",
51
- reference: "product_type",
52
- translatedCount: 4,
53
- totalCount: 96,
54
- },
55
- {
56
- icon: <Buildings />,
57
- label: "Product Tags",
58
- reference: "product_tag",
59
- translatedCount: 96,
60
- totalCount: 96,
61
- },
62
- {
63
- icon: <Buildings />,
64
- label: "Product Options",
65
- reference: "product_option",
66
- translatedCount: 96,
67
- totalCount: 96,
68
- },
69
- {
70
- icon: <Buildings />,
71
- label: "Product Option Values",
72
- reference: "product_option_value",
73
- translatedCount: 96,
74
- totalCount: 96,
75
- },
76
- ]
77
-
78
24
  export const TranslationList = () => {
79
25
  const { t } = useTranslation()
80
26
 
81
27
  const { store, isPending, isError, error } = useStore()
28
+ const {
29
+ translatable_fields,
30
+ isPending: isTranslationSettingsPending,
31
+ isError: isTranslationSettingsError,
32
+ error: translationSettingsError,
33
+ } = useTranslationSettings()
34
+ const {
35
+ statistics,
36
+ isPending: isTranslationStatisticsPending,
37
+ isError: isTranslationStatisticsError,
38
+ error: translationStatisticsError,
39
+ } = useTranslationStatistics(
40
+ {
41
+ locales:
42
+ store?.supported_locales?.map(
43
+ (suportedLocale) => suportedLocale.locale_code
44
+ ) ?? [],
45
+ entity_types: Object.keys(translatable_fields ?? {}),
46
+ },
47
+ {
48
+ enabled: !!translatable_fields && !!store,
49
+ }
50
+ )
82
51
 
83
- if (isError) {
84
- throw error
52
+ if (isError || isTranslationSettingsError || isTranslationStatisticsError) {
53
+ throw error || translationSettingsError || translationStatisticsError
85
54
  }
86
55
 
87
- const isReady = !!store && !isPending
56
+ const hasLocales = (store?.supported_locales ?? []).length > 0
57
+
58
+ const translatableEntities: TranslatableEntity[] = useMemo(() => {
59
+ if (!translatable_fields || !statistics) {
60
+ return []
61
+ }
62
+
63
+ return Object.entries(translatable_fields).map(([entity, fields]) => {
64
+ const entityStatistics = statistics[entity]
65
+
66
+ return {
67
+ label: entity
68
+ .split("_")
69
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
70
+ .join(" "),
71
+ reference: entity,
72
+ translatableFields: fields,
73
+ translatedCount: entityStatistics.translated,
74
+ totalCount: entityStatistics.expected,
75
+ }
76
+ })
77
+ }, [translatable_fields, statistics])
78
+
79
+ const isReady =
80
+ !!store &&
81
+ !isPending &&
82
+ !isTranslationSettingsPending &&
83
+ !isTranslationStatisticsPending &&
84
+ !!translatable_fields &&
85
+ !!statistics
88
86
 
89
87
  if (!isReady) {
90
88
  return <TwoColumnPageSkeleton sidebarSections={2} />
91
89
  }
92
90
 
93
- const hasLocales = (store?.supported_locales ?? []).length > 0
94
-
95
91
  return (
96
92
  <TwoColumnPage
97
93
  widgets={{
@@ -109,7 +105,7 @@ export const TranslationList = () => {
109
105
  </Text>
110
106
  </Container>
111
107
  <TranslationListSection
112
- entities={TRANSLATABLE_ENTITIES}
108
+ entities={translatableEntities}
113
109
  hasLocales={hasLocales}
114
110
  />
115
111
  </TwoColumnPage.Main>
@@ -121,7 +117,9 @@ export const TranslationList = () => {
121
117
  ) ?? []
122
118
  }
123
119
  ></ActiveLocalesSection>
124
- <TranslationsCompletionSection />
120
+ {statistics && (
121
+ <TranslationsCompletionSection statistics={statistics} />
122
+ )}
125
123
  </TwoColumnPage.Sidebar>
126
124
  </TwoColumnPage>
127
125
  )
@@ -18,10 +18,9 @@ import {
18
18
  import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
19
19
  import { useBatchTranslations } from "../../../../../hooks/api/translations"
20
20
  import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
21
- import { REFERENCE_LABEL_MAP } from "../../utils"
22
21
 
23
22
  /**
24
- * Schema for a single locale translation (subrow in DataGrid).
23
+ * Schema for a single locale translation.
25
24
  */
26
25
  const LocaleTranslationSchema = z.object({
27
26
  id: z.string().nullish(),
@@ -50,30 +49,28 @@ export type TranslationsFormSchema = z.infer<typeof TranslationsFormSchema>
50
49
 
51
50
  /**
52
51
  * Row types for the DataGrid.
53
- * Parent rows are entities, subrows are locale translations.
52
+ * Parent rows are entities, subrows are translatable fields.
54
53
  */
55
- export type TranslationRow = EntityRow | LocaleRow
54
+ export type TranslationRow = EntityRow | FieldRow
56
55
 
57
56
  export type EntityRow = {
58
57
  _type: "entity"
59
58
  reference_id: string
60
- subRows: LocaleRow[]
59
+ subRows: FieldRow[]
61
60
  }
62
61
 
63
- export type LocaleRow = {
64
- _type: "locale"
62
+ export type FieldRow = {
63
+ _type: "field"
65
64
  reference_id: string
66
- locale_code: string
67
- locale_name: string
68
- id?: string
65
+ field_name: string
69
66
  }
70
67
 
71
68
  export function isEntityRow(row: TranslationRow): row is EntityRow {
72
69
  return row._type === "entity"
73
70
  }
74
71
 
75
- export function isLocaleRow(row: TranslationRow): row is LocaleRow {
76
- return row._type === "locale"
72
+ export function isFieldRow(row: TranslationRow): row is FieldRow {
73
+ return row._type === "field"
77
74
  }
78
75
 
79
76
  function initTranslationsFormState(
@@ -95,14 +92,10 @@ function initTranslationsFormState(
95
92
  for (const locale of availableLocales) {
96
93
  const key = `${reference.id}:${locale.locale_code}`
97
94
  const existing = existingMap.get(key)
98
- const isDefaultLocale = locale.is_default
99
95
 
100
96
  const fields: Record<string, string> = {}
101
97
  for (const fieldName of translatableFields) {
102
- const fieldValue = isDefaultLocale
103
- ? (existing?.translations?.[fieldName] as string) ??
104
- reference[fieldName]
105
- : (existing?.translations?.[fieldName] as string) ?? ""
98
+ const fieldValue = (existing?.translations?.[fieldName] as string) ?? ""
106
99
  fields[fieldName] = fieldValue
107
100
  }
108
101
 
@@ -123,29 +116,16 @@ function initTranslationsFormState(
123
116
 
124
117
  function buildTranslationRows(
125
118
  references: { id: string; [key: string]: string }[],
126
- availableLocales: AdminStoreLocale[],
127
- translations: HttpTypes.AdminTranslation[]
119
+ translatableFields: string[]
128
120
  ): TranslationRow[] {
129
- // Index existing translations by reference_id:locale_code
130
- const existingMap = new Map<string, HttpTypes.AdminTranslation>()
131
- for (const t of translations) {
132
- existingMap.set(`${t.reference_id}:${t.locale_code}`, t)
133
- }
134
-
135
121
  return references.map((reference) => ({
136
122
  _type: "entity" as const,
137
123
  reference_id: reference.id,
138
- subRows: availableLocales.map((locale) => {
139
- const key = `${reference.id}:${locale.locale_code}`
140
- const existing = existingMap.get(key)
141
- return {
142
- _type: "locale" as const,
143
- reference_id: reference.id,
144
- locale_code: locale.locale_code,
145
- locale_name: locale.locale.name,
146
- id: existing?.id,
147
- }
148
- }),
124
+ subRows: translatableFields.map((fieldName) => ({
125
+ _type: "field" as const,
126
+ reference_id: reference.id,
127
+ field_name: fieldName,
128
+ })),
149
129
  }))
150
130
  }
151
131
 
@@ -209,10 +189,14 @@ const columnHelper = createDataGridHelper<
209
189
  >()
210
190
 
211
191
  function useTranslationsGridColumns({
192
+ entities,
212
193
  translatableFields,
194
+ availableLocales,
213
195
  modalFields = [],
214
196
  }: {
197
+ entities: { id: string; [key: string]: string }[]
215
198
  translatableFields: string[]
199
+ availableLocales: AdminStoreLocale[]
216
200
  modalFields?: string[]
217
201
  }) {
218
202
  const { t } = useTranslation()
@@ -220,8 +204,9 @@ function useTranslationsGridColumns({
220
204
  const columns: ColumnDef<TranslationRow>[] = useMemo(() => {
221
205
  return [
222
206
  columnHelper.column({
223
- id: "locale",
224
- header: t("translations.bulk.mainColumn"),
207
+ id: "field",
208
+ name: "field",
209
+ header: undefined,
225
210
  cell: (context) => {
226
211
  const row = context.row.original
227
212
 
@@ -234,35 +219,67 @@ function useTranslationsGridColumns({
234
219
  return (
235
220
  <DataGrid.ReadonlyCell context={context} color="normal">
236
221
  <div className="flex h-full w-full items-center gap-x-2 overflow-hidden">
237
- <span className="truncate">{row.locale_name}</span>
222
+ <span className="truncate">
223
+ {t(`fields.${row.field_name}`, {
224
+ defaultValue: row.field_name,
225
+ })}
226
+ </span>
238
227
  </div>
239
228
  </DataGrid.ReadonlyCell>
240
229
  )
241
230
  },
242
231
  disableHiding: true,
243
232
  }),
244
- ...translatableFields.map((fieldName) => {
245
- const useModal = modalFields.includes(fieldName)
233
+ columnHelper.column({
234
+ id: "original",
235
+ name: "original",
236
+ header: t("general.original"),
237
+ cell: (context) => {
238
+ const row = context.row.original
239
+
240
+ if (isEntityRow(row)) {
241
+ return (
242
+ <DataGrid.ReadonlyCell context={context}></DataGrid.ReadonlyCell>
243
+ )
244
+ }
246
245
 
246
+ const entity = entities.find(
247
+ (entity) => entity.id === row.reference_id
248
+ )
249
+ if (!entity) {
250
+ return null
251
+ }
252
+
253
+ return (
254
+ <DataGrid.ReadonlyCell context={context}>
255
+ {entity[row.field_name]}
256
+ </DataGrid.ReadonlyCell>
257
+ )
258
+ },
259
+ }),
260
+ ...availableLocales.map((locale) => {
247
261
  return columnHelper.column({
248
- id: fieldName,
249
- header: t(`fields.${fieldName}`, { defaultValue: fieldName }),
262
+ id: locale.locale_code,
263
+ name: locale.locale.name,
264
+ header: () => locale.locale.name,
250
265
  cell: (context) => {
251
266
  const row = context.row.original
252
267
 
253
268
  if (isEntityRow(row)) {
254
269
  return (
255
- <DataGrid.ReadonlyCell context={context}>
256
- <span className="text-ui-fg-muted">—</span>
257
- </DataGrid.ReadonlyCell>
270
+ <DataGrid.ReadonlyCell
271
+ context={context}
272
+ ></DataGrid.ReadonlyCell>
258
273
  )
259
274
  }
260
275
 
276
+ const useModal = modalFields.includes(row.field_name)
277
+
261
278
  if (useModal) {
262
279
  return (
263
280
  <DataGrid.ExpandableTextCell
264
281
  context={context}
265
- fieldLabel={fieldName}
282
+ fieldLabel={row.field_name}
266
283
  />
267
284
  )
268
285
  }
@@ -276,13 +293,13 @@ function useTranslationsGridColumns({
276
293
  return null
277
294
  }
278
295
 
279
- return `entities.${row.reference_id}.locales.${row.locale_code}.fields.${fieldName}`
296
+ return `entities.${row.reference_id}.locales.${locale.locale_code}.fields.${row.field_name}`
280
297
  },
281
298
  type: "text",
282
299
  })
283
300
  }),
284
301
  ]
285
- }, [t, translatableFields, modalFields])
302
+ }, [t, translatableFields, availableLocales, modalFields])
286
303
 
287
304
  return columns
288
305
  }
@@ -294,6 +311,10 @@ type TranslationsEditFormProps = {
294
311
  availableLocales: AdminStoreLocale[]
295
312
  translatableFields: string[]
296
313
  modalFields?: string[]
314
+ fetchNextPage: () => void
315
+ hasNextPage: boolean
316
+ isFetchingNextPage: boolean
317
+ referenceCount: number
297
318
  }
298
319
 
299
320
  export const TranslationsEditForm = ({
@@ -303,12 +324,20 @@ export const TranslationsEditForm = ({
303
324
  availableLocales,
304
325
  translatableFields,
305
326
  modalFields = [],
327
+ fetchNextPage,
328
+ hasNextPage,
329
+ isFetchingNextPage,
330
+ referenceCount,
306
331
  }: TranslationsEditFormProps) => {
307
332
  const { t } = useTranslation()
308
333
  const { handleSuccess, setCloseOnEscape } = useRouteModal()
309
334
  const direction = useDocumentDirection()
310
335
 
311
336
  const entities = useMemo(() => references, [references])
337
+ const totalCount = useMemo(
338
+ () => referenceCount * (translatableFields.length + 1),
339
+ [referenceCount, translatableFields]
340
+ )
312
341
 
313
342
  const initialState = useRef(
314
343
  initTranslationsFormState(
@@ -325,8 +354,8 @@ export const TranslationsEditForm = ({
325
354
  })
326
355
 
327
356
  const rows = useMemo(
328
- () => buildTranslationRows(entities, availableLocales, translations),
329
- [entities, availableLocales, translations]
357
+ () => buildTranslationRows(entities, translatableFields),
358
+ [entities, translatableFields]
330
359
  )
331
360
 
332
361
  const { mutateAsync, isPending } = useBatchTranslations(entityType)
@@ -349,23 +378,53 @@ export const TranslationsEditForm = ({
349
378
  return
350
379
  }
351
380
 
352
- await mutateAsync(payload, {
353
- onSuccess: () => {
354
- toast.success(
355
- t("translations.edit.successToast", {
356
- defaultValue: "Translations updated successfully",
357
- })
358
- )
359
- handleSuccess()
360
- },
361
- onError: (error) => {
362
- toast.error(error.message)
363
- },
364
- })
381
+ const BATCH_SIZE = 150
382
+ const totalItems =
383
+ payload.create.length + payload.update.length + payload.delete.length
384
+ const batchCount = Math.ceil(totalItems / BATCH_SIZE)
385
+
386
+ for (let i = 0; i < batchCount; i++) {
387
+ let currentBatchAvailable = BATCH_SIZE
388
+ const currentBatch: HttpTypes.AdminBatchTranslations = {
389
+ create: [],
390
+ update: [],
391
+ delete: [],
392
+ }
393
+ if (payload.create.length > 0) {
394
+ currentBatch.create = payload.create.splice(0, currentBatchAvailable)
395
+ currentBatchAvailable -= currentBatch.create.length
396
+ }
397
+ if (payload.update.length > 0) {
398
+ currentBatch.update = payload.update.splice(0, currentBatchAvailable)
399
+ currentBatchAvailable -= currentBatch.update.length
400
+ }
401
+ if (payload.delete.length > 0) {
402
+ currentBatch.delete = payload.delete.splice(0, currentBatchAvailable)
403
+ currentBatchAvailable -= currentBatch.delete.length
404
+ }
405
+
406
+ await mutateAsync(currentBatch, {
407
+ onSuccess: () => {
408
+ if (i === batchCount - 1) {
409
+ toast.success(
410
+ t("translations.edit.successToast", {
411
+ defaultValue: "Translations updated successfully",
412
+ })
413
+ )
414
+ handleSuccess()
415
+ }
416
+ },
417
+ onError: (error) => {
418
+ toast.error(error.message)
419
+ },
420
+ })
421
+ }
365
422
  })
366
423
 
367
424
  const columns = useTranslationsGridColumns({
425
+ entities,
368
426
  translatableFields,
427
+ availableLocales,
369
428
  modalFields,
370
429
  })
371
430
 
@@ -381,7 +440,10 @@ export const TranslationsEditForm = ({
381
440
  <div className="-my-2 w-full border-l">
382
441
  <ProgressTabs.List className="justify-start-start flex w-full items-center">
383
442
  <ProgressTabs.Trigger value={entityType}>
384
- {REFERENCE_LABEL_MAP[entityType]}
443
+ {entityType
444
+ .split("_")
445
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
446
+ .join(" ")}
385
447
  </ProgressTabs.Trigger>
386
448
  </ProgressTabs.List>
387
449
  </div>
@@ -401,6 +463,10 @@ export const TranslationsEditForm = ({
401
463
  }}
402
464
  state={form}
403
465
  onEditingChange={(editing) => setCloseOnEscape(!editing)}
466
+ totalRowCount={totalCount}
467
+ onFetchMore={fetchNextPage}
468
+ isFetchingMore={isFetchingNextPage}
469
+ hasNextPage={hasNextPage}
404
470
  />
405
471
  </ProgressTabs.Content>
406
472
  </RouteFocusModal.Body>
@@ -1,9 +1,14 @@
1
1
  import { useNavigate, useSearchParams } from "react-router-dom"
2
- import { useReferenceTranslations, useStore } from "../../../hooks/api"
2
+ import {
3
+ useReferenceTranslations,
4
+ useStore,
5
+ useTranslationSettings,
6
+ } from "../../../hooks/api"
3
7
  import { TranslationsEditForm } from "./components/translations-edit-form"
4
8
  import { useEffect } from "react"
5
9
  import { RouteFocusModal } from "../../../components/modals"
6
10
  import { useFeatureFlag } from "../../../providers/feature-flag-provider"
11
+ import { keepPreviousData } from "@tanstack/react-query"
7
12
 
8
13
  export const TranslationsEdit = () => {
9
14
  const isTranslationsEnabled = useFeatureFlag("translation")
@@ -19,17 +24,32 @@ export const TranslationsEdit = () => {
19
24
  }
20
25
  }, [reference, navigate, isTranslationsEnabled])
21
26
 
27
+ const {
28
+ translatable_fields,
29
+ isPending: isTranslationSettingsPending,
30
+ isError: isTranslationSettingsError,
31
+ error: translationSettingsError,
32
+ } = useTranslationSettings({ entity_type: reference! })
33
+
22
34
  const {
23
35
  translations,
24
36
  references,
25
- translatableFields,
37
+ fetchNextPage,
38
+ count,
39
+ isFetchingNextPage,
40
+ hasNextPage,
26
41
  isPending,
27
42
  isError,
28
43
  error,
29
- } = useReferenceTranslations(reference!, referenceIdParam, {
30
- enabled: !!reference,
31
- })
32
-
44
+ } = useReferenceTranslations(
45
+ reference!,
46
+ translatable_fields?.[reference!] ?? [],
47
+ referenceIdParam,
48
+ {
49
+ enabled: !!translatable_fields && !!reference,
50
+ placeholderData: keepPreviousData,
51
+ }
52
+ )
33
53
  const {
34
54
  store,
35
55
  isPending: isStorePending,
@@ -40,13 +60,14 @@ export const TranslationsEdit = () => {
40
60
  const ready =
41
61
  !isPending &&
42
62
  !!translations &&
43
- !!translatableFields &&
63
+ !!translatable_fields &&
64
+ !isTranslationSettingsPending &&
44
65
  !!references &&
45
66
  !isStorePending &&
46
67
  !!store
47
68
 
48
- if (isError || isStoreError) {
49
- throw error || storeError
69
+ if (isError || isStoreError || isTranslationSettingsError) {
70
+ throw error || storeError || translationSettingsError
50
71
  }
51
72
 
52
73
  return (
@@ -57,9 +78,12 @@ export const TranslationsEdit = () => {
57
78
  references={references}
58
79
  entityType={reference!}
59
80
  availableLocales={store?.supported_locales ?? []}
60
- // TODO: change this to get it from the entity translation config when we have it
61
- translatableFields={translatableFields}
62
- modalFields={translatableFields}
81
+ translatableFields={translatable_fields[reference!]}
82
+ modalFields={translatable_fields[reference!]}
83
+ fetchNextPage={fetchNextPage}
84
+ hasNextPage={hasNextPage}
85
+ isFetchingNextPage={isFetchingNextPage}
86
+ referenceCount={count}
63
87
  />
64
88
  )}
65
89
  </RouteFocusModal>
@@ -1 +0,0 @@
1
- export * from "./reference-label-map"
@@ -1,10 +0,0 @@
1
- export const REFERENCE_LABEL_MAP: Record<string, string> = {
2
- product: "Products",
3
- product_variant: "Product Variants",
4
- product_category: "Product Categories",
5
- product_collection: "Product Collections",
6
- product_type: "Product Types",
7
- product_tag: "Product Tags",
8
- product_option: "Product Options",
9
- product_option_value: "Product Option Values",
10
- }