@medusajs/dashboard 2.10.4-snapshot-20250922165717 → 2.10.4-snapshot-20250923121159

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 (48) hide show
  1. package/dist/{add-campaign-promotions-FE4BXGVN.mjs → add-campaign-promotions-JOVLXLS4.mjs} +3 -3
  2. package/dist/{api-key-management-detail-SAVBCKX7.mjs → api-key-management-detail-I7T67TXF.mjs} +1 -1
  3. package/dist/{api-key-management-sales-channels-WL5L5XWM.mjs → api-key-management-sales-channels-6GN6RVZ2.mjs} +1 -1
  4. package/dist/app.css +0 -3
  5. package/dist/app.js +3330 -3318
  6. package/dist/app.mjs +2 -2
  7. package/dist/{campaign-detail-KTOLZNTA.mjs → campaign-detail-NRZHGINV.mjs} +3 -3
  8. package/dist/{chunk-JO6QASTJ.mjs → chunk-37UXEJF2.mjs} +1 -1
  9. package/dist/{chunk-7YZF3THS.mjs → chunk-BHZAQZYP.mjs} +1 -1
  10. package/dist/{chunk-KMUDF36P.mjs → chunk-JIQQKKLO.mjs} +1 -1
  11. package/dist/{chunk-S45XMWVD.mjs → chunk-JMQ6V54O.mjs} +1 -1
  12. package/dist/{chunk-CGK6IVLN.mjs → chunk-OLUNPPBR.mjs} +1 -1
  13. package/dist/{chunk-IINWRJA6.mjs → chunk-RVOPC44F.mjs} +27 -27
  14. package/dist/{chunk-UNM3LPTG.mjs → chunk-YM4QJC6Y.mjs} +24 -11
  15. package/dist/{chunk-JELVERJM.mjs → chunk-ZJA7VBUR.mjs} +6 -2
  16. package/dist/{customer-group-list-GPIKR66X.mjs → customer-group-list-D26UKQMR.mjs} +1 -1
  17. package/dist/{inventory-detail-5433AAQ2.mjs → inventory-detail-QHL7TJFZ.mjs} +1 -1
  18. package/dist/location-list-62KBWY4T.mjs +316 -0
  19. package/dist/{location-sales-channels-2BOIPBBG.mjs → location-sales-channels-O5XLIPAR.mjs} +1 -1
  20. package/dist/{order-list-ZCMNSZYB.mjs → order-list-73DBATIK.mjs} +2 -2
  21. package/dist/{product-attributes-ZZPEBDCK.mjs → product-attributes-FQDJCNUB.mjs} +3 -3
  22. package/dist/{product-create-FCDCIDCH.mjs → product-create-W37RQLON.mjs} +4 -4
  23. package/dist/{product-detail-2ZUONC23.mjs → product-detail-TANIKAEK.mjs} +4 -4
  24. package/dist/{product-edit-G3Z6FCN6.mjs → product-edit-DO76GHBI.mjs} +3 -3
  25. package/dist/{product-list-WGX66SGI.mjs → product-list-KJ3HXPLB.mjs} +2 -2
  26. package/dist/{product-media-APQKPFTT.mjs → product-media-VG4YM2W6.mjs} +2 -2
  27. package/dist/{product-organization-BYT4TKMZ.mjs → product-organization-OOVUGXNP.mjs} +3 -3
  28. package/dist/{product-sales-channels-UGPAXFAV.mjs → product-sales-channels-QEJRSCAU.mjs} +1 -1
  29. package/dist/{product-shipping-profile-YDN4X6S2.mjs → product-shipping-profile-FFMKOF6B.mjs} +3 -3
  30. package/dist/{promotion-detail-6ZD7Z6BF.mjs → promotion-detail-GONXLJZ2.mjs} +112 -63
  31. package/dist/{promotion-list-GI64LDWI.mjs → promotion-list-NNEMVJ6I.mjs} +3 -3
  32. package/dist/{reset-password-SXA6YKTJ.mjs → reset-password-ANJHGYUE.mjs} +1 -1
  33. package/dist/{sales-channel-list-ADIJMXNV.mjs → sales-channel-list-LKVHXUXW.mjs} +1 -1
  34. package/dist/{tax-region-create-W3K5IFD3.mjs → tax-region-create-IWM4755I.mjs} +1 -1
  35. package/dist/{user-list-3YFYZFSK.mjs → user-list-MKJLB5CQ.mjs} +1 -1
  36. package/package.json +9 -9
  37. package/src/components/data-table/data-table.tsx +64 -46
  38. package/src/i18n/translations/$schema.json +90 -67
  39. package/src/i18n/translations/en.json +6 -2
  40. package/src/routes/locations/location-list/index.ts +0 -1
  41. package/src/routes/locations/location-list/location-list.tsx +51 -19
  42. package/src/routes/locations/location-list/use-location-list-table-columns.tsx +185 -0
  43. package/src/routes/locations/location-list/use-location-list-table-query.tsx +22 -0
  44. package/dist/chunk-BKJC5BGQ.mjs +0 -53
  45. package/dist/location-list-BKK2PAKF.mjs +0 -297
  46. package/src/routes/locations/location-list/components/location-list-header/index.ts +0 -1
  47. package/src/routes/locations/location-list/components/location-list-header/location-list-header.tsx +0 -21
  48. package/src/routes/locations/location-list/loader.ts +0 -36
@@ -5830,9 +5830,23 @@
5830
5830
  "properties": {
5831
5831
  "description": {
5832
5832
  "type": "string"
5833
+ },
5834
+ "noRecordsMessage": {
5835
+ "type": "string"
5836
+ },
5837
+ "noRecordsMessageEmpty": {
5838
+ "type": "string"
5839
+ },
5840
+ "noRecordsMessageFiltered": {
5841
+ "type": "string"
5833
5842
  }
5834
5843
  },
5835
- "required": ["description"],
5844
+ "required": [
5845
+ "description",
5846
+ "noRecordsMessage",
5847
+ "noRecordsMessageEmpty",
5848
+ "noRecordsMessageFiltered"
5849
+ ],
5836
5850
  "additionalProperties": false
5837
5851
  },
5838
5852
  "create": {
@@ -5872,9 +5886,12 @@
5872
5886
  "properties": {
5873
5887
  "confirmation": {
5874
5888
  "type": "string"
5889
+ },
5890
+ "successToast": {
5891
+ "type": "string"
5875
5892
  }
5876
5893
  },
5877
- "required": ["confirmation"],
5894
+ "required": ["confirmation", "successToast"],
5878
5895
  "additionalProperties": false
5879
5896
  },
5880
5897
  "fulfillmentProviders": {
@@ -11554,6 +11571,70 @@
11554
11571
  ],
11555
11572
  "additionalProperties": false
11556
11573
  },
11574
+ "dateTime": {
11575
+ "type": "object",
11576
+ "properties": {
11577
+ "years_one": {
11578
+ "type": "string"
11579
+ },
11580
+ "years_other": {
11581
+ "type": "string"
11582
+ },
11583
+ "months_one": {
11584
+ "type": "string"
11585
+ },
11586
+ "months_other": {
11587
+ "type": "string"
11588
+ },
11589
+ "weeks_one": {
11590
+ "type": "string"
11591
+ },
11592
+ "weeks_other": {
11593
+ "type": "string"
11594
+ },
11595
+ "days_one": {
11596
+ "type": "string"
11597
+ },
11598
+ "days_other": {
11599
+ "type": "string"
11600
+ },
11601
+ "hours_one": {
11602
+ "type": "string"
11603
+ },
11604
+ "hours_other": {
11605
+ "type": "string"
11606
+ },
11607
+ "minutes_one": {
11608
+ "type": "string"
11609
+ },
11610
+ "minutes_other": {
11611
+ "type": "string"
11612
+ },
11613
+ "seconds_one": {
11614
+ "type": "string"
11615
+ },
11616
+ "seconds_other": {
11617
+ "type": "string"
11618
+ }
11619
+ },
11620
+ "required": [
11621
+ "years_one",
11622
+ "years_other",
11623
+ "months_one",
11624
+ "months_other",
11625
+ "weeks_one",
11626
+ "weeks_other",
11627
+ "days_one",
11628
+ "days_other",
11629
+ "hours_one",
11630
+ "hours_other",
11631
+ "minutes_one",
11632
+ "minutes_other",
11633
+ "seconds_one",
11634
+ "seconds_other"
11635
+ ],
11636
+ "additionalProperties": false
11637
+ },
11557
11638
  "views": {
11558
11639
  "type": "object",
11559
11640
  "properties": {
@@ -11615,70 +11696,12 @@
11615
11696
  "additionalProperties": false
11616
11697
  }
11617
11698
  },
11618
- "required": ["save", "saveAsNew", "updateDefaultForEveryone", "updateViewName", "prompts"],
11619
- "additionalProperties": false
11620
- },
11621
- "dateTime": {
11622
- "type": "object",
11623
- "properties": {
11624
- "years_one": {
11625
- "type": "string"
11626
- },
11627
- "years_other": {
11628
- "type": "string"
11629
- },
11630
- "months_one": {
11631
- "type": "string"
11632
- },
11633
- "months_other": {
11634
- "type": "string"
11635
- },
11636
- "weeks_one": {
11637
- "type": "string"
11638
- },
11639
- "weeks_other": {
11640
- "type": "string"
11641
- },
11642
- "days_one": {
11643
- "type": "string"
11644
- },
11645
- "days_other": {
11646
- "type": "string"
11647
- },
11648
- "hours_one": {
11649
- "type": "string"
11650
- },
11651
- "hours_other": {
11652
- "type": "string"
11653
- },
11654
- "minutes_one": {
11655
- "type": "string"
11656
- },
11657
- "minutes_other": {
11658
- "type": "string"
11659
- },
11660
- "seconds_one": {
11661
- "type": "string"
11662
- },
11663
- "seconds_other": {
11664
- "type": "string"
11665
- }
11666
- },
11667
11699
  "required": [
11668
- "years_one",
11669
- "years_other",
11670
- "months_one",
11671
- "months_other",
11672
- "weeks_one",
11673
- "weeks_other",
11674
- "days_one",
11675
- "days_other",
11676
- "hours_one",
11677
- "hours_other",
11678
- "minutes_one",
11679
- "minutes_other",
11680
- "seconds_one",
11681
- "seconds_other"
11700
+ "save",
11701
+ "saveAsNew",
11702
+ "updateDefaultForEveryone",
11703
+ "updateViewName",
11704
+ "prompts"
11682
11705
  ],
11683
11706
  "additionalProperties": false
11684
11707
  }
@@ -11736,8 +11759,8 @@
11736
11759
  "statuses",
11737
11760
  "labels",
11738
11761
  "fields",
11739
- "views",
11740
- "dateTime"
11762
+ "dateTime",
11763
+ "views"
11741
11764
  ],
11742
11765
  "additionalProperties": false
11743
11766
  }
@@ -1534,7 +1534,10 @@
1534
1534
  "stockLocations": {
1535
1535
  "domain": "Locations & Shipping",
1536
1536
  "list": {
1537
- "description": "Manage your store's stock locations and shipping options."
1537
+ "description": "Manage your store's stock locations and shipping options.",
1538
+ "noRecordsMessage": "No records",
1539
+ "noRecordsMessageEmpty": "No locations found",
1540
+ "noRecordsMessageFiltered": "No locations found matching the filters"
1538
1541
  },
1539
1542
  "create": {
1540
1543
  "header": "Create Stock Location",
@@ -1547,7 +1550,8 @@
1547
1550
  "successToast": "Location {{name}} was successfully updated."
1548
1551
  },
1549
1552
  "delete": {
1550
- "confirmation": "You are about to delete the stock location \"{{name}}\". This action cannot be undone."
1553
+ "confirmation": "You are about to delete the stock location \"{{name}}\". This action cannot be undone.",
1554
+ "successToast": "Location \"{{name}}\" was successfully deleted."
1551
1555
  },
1552
1556
  "fulfillmentProviders": {
1553
1557
  "header": "Fulfillment Providers",
@@ -1,2 +1 @@
1
- export { shippingListLoader as loader } from "./loader"
2
1
  export { LocationList as Component } from "./location-list"
@@ -1,34 +1,40 @@
1
1
  import { ShoppingBag, TruckFast } from "@medusajs/icons"
2
2
  import { Container, Heading } from "@medusajs/ui"
3
3
  import { useTranslation } from "react-i18next"
4
- import { useLoaderData } from "react-router-dom"
5
4
 
6
5
  import { useStockLocations } from "../../../hooks/api/stock-locations"
7
- import LocationListItem from "./components/location-list-item/location-list-item"
8
6
  import { LOCATION_LIST_FIELDS } from "./constants"
9
- import { shippingListLoader } from "./loader"
7
+ import { useLocationListTableColumns } from "./use-location-list-table-columns"
8
+ import { useLocationListTableQuery } from "./use-location-list-table-query"
10
9
 
10
+ import { DataTable } from "../../../components/data-table"
11
11
  import { SidebarLink } from "../../../components/common/sidebar-link/sidebar-link"
12
12
  import { TwoColumnPage } from "../../../components/layout/pages"
13
13
  import { useExtension } from "../../../providers/extension-provider"
14
- import { LocationListHeader } from "./components/location-list-header"
14
+
15
+ const PAGE_SIZE = 20
16
+ const PREFIX = "loc"
15
17
 
16
18
  export function LocationList() {
17
- const initialData = useLoaderData() as Awaited<
18
- ReturnType<typeof shippingListLoader>
19
- >
19
+ const { t } = useTranslation()
20
+
21
+ const searchParams = useLocationListTableQuery({
22
+ pageSize: PAGE_SIZE,
23
+ prefix: PREFIX,
24
+ })
20
25
 
21
26
  const {
22
27
  stock_locations: stockLocations = [],
28
+ count,
23
29
  isError,
24
30
  error,
25
- } = useStockLocations(
26
- {
27
- fields: LOCATION_LIST_FIELDS,
28
- },
29
- { initialData }
30
- )
31
+ isLoading,
32
+ } = useStockLocations({
33
+ fields: LOCATION_LIST_FIELDS,
34
+ ...searchParams,
35
+ })
31
36
 
37
+ const columns = useLocationListTableColumns()
32
38
  const { getWidgets } = useExtension()
33
39
 
34
40
  if (isError) {
@@ -46,12 +52,38 @@ export function LocationList() {
46
52
  showJSON
47
53
  >
48
54
  <TwoColumnPage.Main>
49
- <LocationListHeader />
50
- <div className="flex flex-col gap-3 lg:col-span-2">
51
- {stockLocations.map((location) => (
52
- <LocationListItem key={location.id} location={location} />
53
- ))}
54
- </div>
55
+ <Container className="flex flex-col divide-y p-0">
56
+ <DataTable
57
+ data={stockLocations}
58
+ columns={columns}
59
+ rowCount={count}
60
+ pageSize={PAGE_SIZE}
61
+ getRowId={(row) => row.id}
62
+ heading={t("stockLocations.domain")}
63
+ subHeading={t("stockLocations.list.description")}
64
+ emptyState={{
65
+ empty: {
66
+ heading: t("stockLocations.list.noRecordsMessage"),
67
+ description: t("stockLocations.list.noRecordsMessageEmpty"),
68
+ },
69
+ filtered: {
70
+ heading: t("stockLocations.list.noRecordsMessage"),
71
+ description: t("stockLocations.list.noRecordsMessageFiltered"),
72
+ },
73
+ }}
74
+ actions={[
75
+ {
76
+ label: t("actions.create"),
77
+ to: "create",
78
+ },
79
+ ]}
80
+ isLoading={isLoading}
81
+ rowHref={(row) => `/settings/locations/${row.id}`}
82
+ enableSearch={true}
83
+ prefix={PREFIX}
84
+ layout="fill"
85
+ />
86
+ </Container>
55
87
  </TwoColumnPage.Main>
56
88
  <TwoColumnPage.Sidebar>
57
89
  <LinksSection />
@@ -0,0 +1,185 @@
1
+ import { HttpTypes } from "@medusajs/types"
2
+ import { PencilSquare, Trash } from "@medusajs/icons"
3
+ import {
4
+ createDataTableColumnHelper,
5
+ StatusBadge,
6
+ toast,
7
+ usePrompt,
8
+ } from "@medusajs/ui"
9
+ import { useTranslation } from "react-i18next"
10
+ import { useMemo } from "react"
11
+ import { useNavigate } from "react-router-dom"
12
+ import { FetchError } from "@medusajs/js-sdk"
13
+
14
+ import { PlaceholderCell } from "../../../components/table/table-cells/common/placeholder-cell"
15
+ import { getFormattedAddress } from "../../../lib/addresses"
16
+ import { FulfillmentSetType } from "../common/constants"
17
+ import { queryClient } from "../../../lib/query-client"
18
+ import { stockLocationsQueryKeys } from "../../../hooks/api/stock-locations"
19
+ import { ListSummary } from "../../../components/common/list-summary"
20
+ import { sdk } from "../../../lib/client"
21
+
22
+ const columnHelper = createDataTableColumnHelper<HttpTypes.AdminStockLocation>()
23
+
24
+ export const useLocationListTableColumns = () => {
25
+ const { t } = useTranslation()
26
+ const navigate = useNavigate()
27
+ const prompt = usePrompt()
28
+
29
+ const handleDelete = async (location: HttpTypes.AdminStockLocation) => {
30
+ const result = await prompt({
31
+ title: t("general.areYouSure"),
32
+ description: t("stockLocations.delete.confirmation", {
33
+ name: location.name,
34
+ }),
35
+ confirmText: t("actions.remove"),
36
+ cancelText: t("actions.cancel"),
37
+ })
38
+
39
+ if (!result) {
40
+ return
41
+ }
42
+
43
+ try {
44
+ await sdk.admin.stockLocation.delete(location.id)
45
+ queryClient.invalidateQueries({
46
+ queryKey: stockLocationsQueryKeys.lists(),
47
+ })
48
+
49
+ queryClient.invalidateQueries({
50
+ queryKey: stockLocationsQueryKeys.detail(location.id),
51
+ })
52
+
53
+ toast.success(
54
+ t("stockLocations.delete.successToast", {
55
+ name: location.name,
56
+ })
57
+ )
58
+ } catch (e) {
59
+ toast.error((e as FetchError).message)
60
+ }
61
+ }
62
+
63
+ return useMemo(
64
+ () => [
65
+ columnHelper.accessor("name", {
66
+ header: t("fields.name"),
67
+ cell: ({ getValue }) => {
68
+ const name = getValue()
69
+ if (!name) {
70
+ return <PlaceholderCell />
71
+ }
72
+
73
+ return (
74
+ <span className="text-ui-fg-subtle text-small truncate">
75
+ {name}
76
+ </span>
77
+ )
78
+ },
79
+ }),
80
+ columnHelper.accessor("address", {
81
+ header: t("fields.address"),
82
+ cell: ({ getValue, row }) => {
83
+ const address = getValue()
84
+ const location = row.original
85
+
86
+ if (!address) {
87
+ return <PlaceholderCell />
88
+ }
89
+
90
+ return (
91
+ <div className="flex flex-col">
92
+ <span className="text-ui-fg-subtle text-small truncate">
93
+ {getFormattedAddress({
94
+ address: location.address as HttpTypes.AdminOrderAddress,
95
+ }).join(", ")}
96
+ </span>
97
+ </div>
98
+ )
99
+ },
100
+ }),
101
+ columnHelper.accessor("fulfillment_sets", {
102
+ id: "shipping_fulfillment",
103
+ header: t("stockLocations.fulfillmentSets.shipping.header"),
104
+ cell: ({ getValue }) => {
105
+ const fulfillmentSets = getValue()
106
+ const shippingSet = fulfillmentSets?.find(
107
+ (f) => f.type === FulfillmentSetType.Shipping
108
+ )
109
+ const fulfillmentSetExists = !!shippingSet
110
+
111
+ return (
112
+ <StatusBadge color={fulfillmentSetExists ? "green" : "grey"}>
113
+ {t(
114
+ fulfillmentSetExists ? "statuses.enabled" : "statuses.disabled"
115
+ )}
116
+ </StatusBadge>
117
+ )
118
+ },
119
+ }),
120
+ columnHelper.accessor("fulfillment_sets", {
121
+ id: "pickup_fulfillment",
122
+ header: t("stockLocations.fulfillmentSets.pickup.header"),
123
+ cell: ({ getValue }) => {
124
+ const fulfillmentSets = getValue()
125
+ const pickupSet = fulfillmentSets?.find(
126
+ (f) => f.type === FulfillmentSetType.Pickup
127
+ )
128
+ const fulfillmentSetExists = !!pickupSet
129
+
130
+ return (
131
+ <StatusBadge color={fulfillmentSetExists ? "green" : "grey"}>
132
+ {t(
133
+ fulfillmentSetExists ? "statuses.enabled" : "statuses.disabled"
134
+ )}
135
+ </StatusBadge>
136
+ )
137
+ },
138
+ }),
139
+ columnHelper.accessor("sales_channels", {
140
+ header: t("stockLocations.salesChannels.label"),
141
+ cell: ({ getValue }) => {
142
+ const salesChannels = getValue()
143
+
144
+ if (!salesChannels?.length) {
145
+ return <PlaceholderCell />
146
+ }
147
+
148
+ return (
149
+ <div className="flex items-center">
150
+ <ListSummary
151
+ inline
152
+ n={1}
153
+ list={salesChannels.map((s) => s.name)}
154
+ />
155
+ </div>
156
+ )
157
+ },
158
+ }),
159
+ columnHelper.action({
160
+ actions: (ctx) => {
161
+ const location = ctx.row.original
162
+ return [
163
+ [
164
+ {
165
+ icon: <PencilSquare />,
166
+ label: t("actions.edit"),
167
+ onClick: () => {
168
+ navigate(`/settings/locations/${location.id}/edit`)
169
+ },
170
+ },
171
+ ],
172
+ [
173
+ {
174
+ icon: <Trash />,
175
+ label: t("actions.delete"),
176
+ onClick: () => handleDelete(location),
177
+ },
178
+ ],
179
+ ]
180
+ },
181
+ }),
182
+ ],
183
+ []
184
+ )
185
+ }
@@ -0,0 +1,22 @@
1
+ import { HttpTypes } from "@medusajs/types"
2
+ import { useQueryParams } from "../../../hooks/use-query-params"
3
+
4
+ export const useLocationListTableQuery = ({
5
+ pageSize = 20,
6
+ prefix,
7
+ }: {
8
+ pageSize?: number
9
+ prefix?: string
10
+ }) => {
11
+ const queryObject = useQueryParams(["order", "offset", "q"], prefix)
12
+
13
+ const { offset, ...rest } = queryObject
14
+
15
+ const searchParams: HttpTypes.AdminStockLocationListParams = {
16
+ limit: pageSize,
17
+ offset: offset ? Number(offset) : 0,
18
+ ...rest,
19
+ }
20
+
21
+ return searchParams
22
+ }
@@ -1,53 +0,0 @@
1
- // src/components/common/badge-list-summary/badge-list-summary.tsx
2
- import { Badge, Tooltip, clx } from "@medusajs/ui";
3
- import { useTranslation } from "react-i18next";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
- var BadgeListSummary = ({
6
- list,
7
- className,
8
- inline,
9
- rounded = false,
10
- n = 2
11
- }) => {
12
- const { t } = useTranslation();
13
- const title = t("general.plusCount", {
14
- count: list.length - n
15
- });
16
- return /* @__PURE__ */ jsxs(
17
- "div",
18
- {
19
- className: clx(
20
- "text-ui-fg-subtle txt-compact-small gap-x-2 overflow-hidden",
21
- {
22
- "inline-flex": inline,
23
- flex: !inline
24
- },
25
- className
26
- ),
27
- children: [
28
- list.slice(0, n).map((item) => {
29
- return /* @__PURE__ */ jsx(Badge, { rounded: rounded ? "full" : "base", size: "2xsmall", children: item }, item);
30
- }),
31
- list.length > n && /* @__PURE__ */ jsx("div", { className: "whitespace-nowrap", children: /* @__PURE__ */ jsx(
32
- Tooltip,
33
- {
34
- content: /* @__PURE__ */ jsx("ul", { children: list.slice(n).map((c) => /* @__PURE__ */ jsx("li", { children: c }, c)) }),
35
- children: /* @__PURE__ */ jsx(
36
- Badge,
37
- {
38
- rounded: rounded ? "full" : "base",
39
- size: "2xsmall",
40
- className: "cursor-default whitespace-nowrap",
41
- children: title
42
- }
43
- )
44
- }
45
- ) })
46
- ]
47
- }
48
- );
49
- };
50
-
51
- export {
52
- BadgeListSummary
53
- };