@medusajs/dashboard 2.11.4-preview-20251107180141 → 2.11.4-preview-20251108000302

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -188039,6 +188039,35 @@ var init_utils14 = __esm({
188039
188039
  }
188040
188040
  });
188041
188041
 
188042
+ // src/dashboard-app/utils/sort-menu-items-by-rank.ts
188043
+ function sortMenuItemsByRank(items) {
188044
+ const sortedItems = items.sort((a, b) => {
188045
+ if (a.rank !== void 0 && b.rank !== void 0) {
188046
+ return a.rank - b.rank;
188047
+ }
188048
+ if (a.rank !== void 0) {
188049
+ return -1;
188050
+ }
188051
+ if (b.rank !== void 0) {
188052
+ return 1;
188053
+ }
188054
+ return 0;
188055
+ });
188056
+ sortedItems.forEach((item) => {
188057
+ if (item.items && item.items.length > 0) {
188058
+ item.items = sortMenuItemsByRank(
188059
+ item.items
188060
+ );
188061
+ }
188062
+ });
188063
+ return sortedItems;
188064
+ }
188065
+ var init_sort_menu_items_by_rank = __esm({
188066
+ "src/dashboard-app/utils/sort-menu-items-by-rank.ts"() {
188067
+ "use strict";
188068
+ }
188069
+ });
188070
+
188042
188071
  // src/dashboard-app/dashboard-app.tsx
188043
188072
  var import_admin_shared, import_react_router_dom247, import_jsx_runtime684, OPTIONAL_LAST_SEGMENT_MATCH, DashboardApp;
188044
188073
  var init_dashboard_app = __esm({
@@ -188050,6 +188079,7 @@ var init_dashboard_app = __esm({
188050
188079
  init_translations();
188051
188080
  init_get_route_map();
188052
188081
  init_utils14();
188082
+ init_sort_menu_items_by_rank();
188053
188083
  import_jsx_runtime684 = require("react/jsx-runtime");
188054
188084
  OPTIONAL_LAST_SEGMENT_MATCH = /\/([^\/])+\?$/;
188055
188085
  DashboardApp = class {
@@ -188159,6 +188189,7 @@ var init_dashboard_app = __esm({
188159
188189
  icon: item.icon ? /* @__PURE__ */ (0, import_jsx_runtime684.jsx)(item.icon, {}) : void 0,
188160
188190
  items: [],
188161
188191
  nested: item.nested,
188192
+ rank: item.rank,
188162
188193
  translationNs: item.translationNs
188163
188194
  };
188164
188195
  if (parentPath !== "/" && tempRegistry[parentPath]) {
@@ -188174,6 +188205,10 @@ var init_dashboard_app = __esm({
188174
188205
  }
188175
188206
  tempRegistry[item.path] = navItem;
188176
188207
  });
188208
+ registry.forEach((items, key) => {
188209
+ const sorted = sortMenuItemsByRank(items);
188210
+ registry.set(key, sorted);
188211
+ });
188177
188212
  return registry;
188178
188213
  }
188179
188214
  populateForm(plugins) {
package/dist/app.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DashboardApp
3
- } from "./chunk-L42C44TT.mjs";
3
+ } from "./chunk-Z6WB7TZP.mjs";
4
4
  import "./chunk-NQIC7ZFS.mjs";
5
5
  import "./chunk-ONB3JEHR.mjs";
6
6
  import "./chunk-YCDDT44O.mjs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getLinkedFields
3
- } from "./chunk-L42C44TT.mjs";
3
+ } from "./chunk-Z6WB7TZP.mjs";
4
4
 
5
5
  // src/routes/products/product-detail/constants.ts
6
6
  var PRODUCT_DETAIL_FIELDS = getLinkedFields(
@@ -92515,7 +92515,7 @@ function getRouteMap({
92515
92515
  children: [
92516
92516
  {
92517
92517
  path: "create",
92518
- lazy: () => import("./product-create-4RYWBBFD.mjs")
92518
+ lazy: () => import("./product-create-NAXSYJ5M.mjs")
92519
92519
  },
92520
92520
  {
92521
92521
  path: "import",
@@ -92531,7 +92531,7 @@ function getRouteMap({
92531
92531
  path: ":id",
92532
92532
  errorElement: /* @__PURE__ */ jsx17(ErrorBoundary, {}),
92533
92533
  lazy: async () => {
92534
- const { Breadcrumb, loader } = await import("./product-detail-VUAVAV4Y.mjs");
92534
+ const { Breadcrumb, loader } = await import("./product-detail-MPZU2WNR.mjs");
92535
92535
  return {
92536
92536
  Component: Outlet4,
92537
92537
  loader,
@@ -92543,11 +92543,11 @@ function getRouteMap({
92543
92543
  children: [
92544
92544
  {
92545
92545
  path: "",
92546
- lazy: () => import("./product-detail-VUAVAV4Y.mjs"),
92546
+ lazy: () => import("./product-detail-MPZU2WNR.mjs"),
92547
92547
  children: [
92548
92548
  {
92549
92549
  path: "edit",
92550
- lazy: () => import("./product-edit-QRSQ7N2D.mjs")
92550
+ lazy: () => import("./product-edit-DASY4AKG.mjs")
92551
92551
  },
92552
92552
  {
92553
92553
  path: "edit-variant",
@@ -92559,15 +92559,15 @@ function getRouteMap({
92559
92559
  },
92560
92560
  {
92561
92561
  path: "attributes",
92562
- lazy: () => import("./product-attributes-2MOCN4AC.mjs")
92562
+ lazy: () => import("./product-attributes-BLFPZBW3.mjs")
92563
92563
  },
92564
92564
  {
92565
92565
  path: "organization",
92566
- lazy: () => import("./product-organization-FCLESZIL.mjs")
92566
+ lazy: () => import("./product-organization-EO4PRRYO.mjs")
92567
92567
  },
92568
92568
  {
92569
92569
  path: "shipping-profile",
92570
- lazy: () => import("./product-shipping-profile-EKVSMZ6F.mjs")
92570
+ lazy: () => import("./product-shipping-profile-H4FRRBGX.mjs")
92571
92571
  },
92572
92572
  {
92573
92573
  path: "media",
@@ -94042,6 +94042,30 @@ var createRouteMap = (routes, ignore) => {
94042
94042
  return root;
94043
94043
  };
94044
94044
 
94045
+ // src/dashboard-app/utils/sort-menu-items-by-rank.ts
94046
+ function sortMenuItemsByRank(items) {
94047
+ const sortedItems = items.sort((a, b) => {
94048
+ if (a.rank !== void 0 && b.rank !== void 0) {
94049
+ return a.rank - b.rank;
94050
+ }
94051
+ if (a.rank !== void 0) {
94052
+ return -1;
94053
+ }
94054
+ if (b.rank !== void 0) {
94055
+ return 1;
94056
+ }
94057
+ return 0;
94058
+ });
94059
+ sortedItems.forEach((item) => {
94060
+ if (item.items && item.items.length > 0) {
94061
+ item.items = sortMenuItemsByRank(
94062
+ item.items
94063
+ );
94064
+ }
94065
+ });
94066
+ return sortedItems;
94067
+ }
94068
+
94045
94069
  // src/dashboard-app/dashboard-app.tsx
94046
94070
  import { jsx as jsx18 } from "react/jsx-runtime";
94047
94071
  var OPTIONAL_LAST_SEGMENT_MATCH = /\/([^\/])+\?$/;
@@ -94152,6 +94176,7 @@ var DashboardApp = class {
94152
94176
  icon: item.icon ? /* @__PURE__ */ jsx18(item.icon, {}) : void 0,
94153
94177
  items: [],
94154
94178
  nested: item.nested,
94179
+ rank: item.rank,
94155
94180
  translationNs: item.translationNs
94156
94181
  };
94157
94182
  if (parentPath !== "/" && tempRegistry[parentPath]) {
@@ -94167,6 +94192,10 @@ var DashboardApp = class {
94167
94192
  }
94168
94193
  tempRegistry[item.path] = navItem;
94169
94194
  });
94195
+ registry.forEach((items, key) => {
94196
+ const sorted = sortMenuItemsByRank(items);
94197
+ registry.set(key, sorted);
94198
+ });
94170
94199
  return registry;
94171
94200
  }
94172
94201
  populateForm(plugins) {
@@ -12,11 +12,11 @@ import {
12
12
  } from "./chunk-AERWK3TJ.mjs";
13
13
  import {
14
14
  PRODUCT_DETAIL_FIELDS
15
- } from "./chunk-UJXHTZVV.mjs";
15
+ } from "./chunk-DZRLFO3U.mjs";
16
16
  import {
17
17
  FormExtensionZone,
18
18
  useExtendableForm
19
- } from "./chunk-L42C44TT.mjs";
19
+ } from "./chunk-Z6WB7TZP.mjs";
20
20
  import "./chunk-NQIC7ZFS.mjs";
21
21
  import "./chunk-ONB3JEHR.mjs";
22
22
  import "./chunk-YCDDT44O.mjs";
@@ -61,7 +61,7 @@ import {
61
61
  import {
62
62
  FormExtensionZone,
63
63
  useExtendableForm
64
- } from "./chunk-L42C44TT.mjs";
64
+ } from "./chunk-Z6WB7TZP.mjs";
65
65
  import "./chunk-NQIC7ZFS.mjs";
66
66
  import "./chunk-ONB3JEHR.mjs";
67
67
  import "./chunk-YCDDT44O.mjs";
@@ -27,8 +27,8 @@ import {
27
27
  import "./chunk-DZWH2RV6.mjs";
28
28
  import {
29
29
  PRODUCT_DETAIL_FIELDS
30
- } from "./chunk-UJXHTZVV.mjs";
31
- import "./chunk-L42C44TT.mjs";
30
+ } from "./chunk-DZRLFO3U.mjs";
31
+ import "./chunk-Z6WB7TZP.mjs";
32
32
  import "./chunk-NQIC7ZFS.mjs";
33
33
  import "./chunk-ONB3JEHR.mjs";
34
34
  import "./chunk-YCDDT44O.mjs";
@@ -15,11 +15,11 @@ import {
15
15
  } from "./chunk-AERWK3TJ.mjs";
16
16
  import {
17
17
  PRODUCT_DETAIL_FIELDS
18
- } from "./chunk-UJXHTZVV.mjs";
18
+ } from "./chunk-DZRLFO3U.mjs";
19
19
  import {
20
20
  FormExtensionZone,
21
21
  useExtendableForm
22
- } from "./chunk-L42C44TT.mjs";
22
+ } from "./chunk-Z6WB7TZP.mjs";
23
23
  import "./chunk-NQIC7ZFS.mjs";
24
24
  import "./chunk-ONB3JEHR.mjs";
25
25
  import "./chunk-YCDDT44O.mjs";
@@ -17,11 +17,11 @@ import {
17
17
  } from "./chunk-AERWK3TJ.mjs";
18
18
  import {
19
19
  PRODUCT_DETAIL_FIELDS
20
- } from "./chunk-UJXHTZVV.mjs";
20
+ } from "./chunk-DZRLFO3U.mjs";
21
21
  import {
22
22
  FormExtensionZone,
23
23
  useExtendableForm
24
- } from "./chunk-L42C44TT.mjs";
24
+ } from "./chunk-Z6WB7TZP.mjs";
25
25
  import "./chunk-NQIC7ZFS.mjs";
26
26
  import "./chunk-ONB3JEHR.mjs";
27
27
  import "./chunk-YCDDT44O.mjs";
@@ -14,8 +14,8 @@ import {
14
14
  } from "./chunk-AERWK3TJ.mjs";
15
15
  import {
16
16
  PRODUCT_DETAIL_FIELDS
17
- } from "./chunk-UJXHTZVV.mjs";
18
- import "./chunk-L42C44TT.mjs";
17
+ } from "./chunk-DZRLFO3U.mjs";
18
+ import "./chunk-Z6WB7TZP.mjs";
19
19
  import "./chunk-NQIC7ZFS.mjs";
20
20
  import "./chunk-ONB3JEHR.mjs";
21
21
  import "./chunk-YCDDT44O.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medusajs/dashboard",
3
- "version": "2.11.4-preview-20251107180141",
3
+ "version": "2.11.4-preview-20251108000302",
4
4
  "scripts": {
5
5
  "generate:static": "node ./scripts/generate-currencies.js && prettier --write ./src/lib/currencies.ts",
6
6
  "dev": "vite",
@@ -46,10 +46,10 @@
46
46
  "@dnd-kit/utilities": "^3.2.2",
47
47
  "@hookform/error-message": "^2.0.1",
48
48
  "@hookform/resolvers": "3.4.2",
49
- "@medusajs/admin-shared": "2.11.4-preview-20251107180141",
50
- "@medusajs/icons": "2.11.4-preview-20251107180141",
51
- "@medusajs/js-sdk": "2.11.4-preview-20251107180141",
52
- "@medusajs/ui": "4.0.28-preview-20251107180141",
49
+ "@medusajs/admin-shared": "2.11.4-preview-20251108000302",
50
+ "@medusajs/icons": "2.11.4-preview-20251108000302",
51
+ "@medusajs/js-sdk": "2.11.4-preview-20251108000302",
52
+ "@medusajs/ui": "4.0.28-preview-20251108000302",
53
53
  "@radix-ui/react-dialog": "1.1.4",
54
54
  "@radix-ui/react-dismissable-layer": "1.1.4",
55
55
  "@tanstack/react-query": "5.64.2",
@@ -81,10 +81,10 @@
81
81
  "zod": "3.25.76"
82
82
  },
83
83
  "devDependencies": {
84
- "@medusajs/admin-shared": "2.11.4-preview-20251107180141",
85
- "@medusajs/admin-vite-plugin": "2.11.4-preview-20251107180141",
86
- "@medusajs/types": "2.11.4-preview-20251107180141",
87
- "@medusajs/ui-preset": "2.11.4-preview-20251107180141"
84
+ "@medusajs/admin-shared": "2.11.4-preview-20251108000302",
85
+ "@medusajs/admin-vite-plugin": "2.11.4-preview-20251108000302",
86
+ "@medusajs/types": "2.11.4-preview-20251108000302",
87
+ "@medusajs/ui-preset": "2.11.4-preview-20251108000302"
88
88
  },
89
89
  "packageManager": "yarn@3.2.1"
90
90
  }
@@ -0,0 +1,169 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { sortMenuItemsByRank } from "../utils/sort-menu-items-by-rank"
3
+ import { INavItem } from "../../components/layout/nav-item"
4
+
5
+ describe("sortMenuItemsByRank", () => {
6
+ it("should sort items by rank in ascending order", () => {
7
+ const items: INavItem[] = [
8
+ { label: "Third", to: "/third", rank: 3 },
9
+ { label: "First", to: "/first", rank: 1 },
10
+ { label: "Second", to: "/second", rank: 2 },
11
+ ]
12
+
13
+ const sorted = sortMenuItemsByRank(items)
14
+
15
+ expect(sorted[0].label).toBe("First")
16
+ expect(sorted[1].label).toBe("Second")
17
+ expect(sorted[2].label).toBe("Third")
18
+ })
19
+
20
+ it("should place items with rank before items without rank", () => {
21
+ const items: INavItem[] = [
22
+ { label: "No Rank", to: "/no-rank" },
23
+ { label: "Ranked 2", to: "/ranked-2", rank: 2 },
24
+ { label: "Ranked 1", to: "/ranked-1", rank: 1 },
25
+ { label: "Also No Rank", to: "/also-no-rank" },
26
+ ]
27
+
28
+ const sorted = sortMenuItemsByRank(items)
29
+
30
+ expect(sorted[0].label).toBe("Ranked 1")
31
+ expect(sorted[1].label).toBe("Ranked 2")
32
+ expect(sorted[2].label).toBe("No Rank")
33
+ expect(sorted[3].label).toBe("Also No Rank")
34
+ })
35
+
36
+ it("should handle items with rank 0", () => {
37
+ const items: INavItem[] = [
38
+ { label: "Rank 2", to: "/rank-2", rank: 2 },
39
+ { label: "Rank 0", to: "/rank-0", rank: 0 },
40
+ { label: "Rank 1", to: "/rank-1", rank: 1 },
41
+ ]
42
+
43
+ const sorted = sortMenuItemsByRank(items)
44
+
45
+ expect(sorted[0].label).toBe("Rank 0")
46
+ expect(sorted[1].label).toBe("Rank 1")
47
+ expect(sorted[2].label).toBe("Rank 2")
48
+ })
49
+
50
+ it("should handle negative ranks", () => {
51
+ const items: INavItem[] = [
52
+ { label: "Rank 1", to: "/rank-1", rank: 1 },
53
+ { label: "Rank -1", to: "/rank-minus-1", rank: -1 },
54
+ { label: "Rank 0", to: "/rank-0", rank: 0 },
55
+ ]
56
+
57
+ const sorted = sortMenuItemsByRank(items)
58
+
59
+ expect(sorted[0].label).toBe("Rank -1")
60
+ expect(sorted[1].label).toBe("Rank 0")
61
+ expect(sorted[2].label).toBe("Rank 1")
62
+ })
63
+
64
+ it("should sort nested items independently", () => {
65
+ const items: INavItem[] = [
66
+ {
67
+ label: "Parent 2",
68
+ to: "/parent-2",
69
+ rank: 2,
70
+ items: [
71
+ { label: "Child 2B", to: "/child-2b", rank: 2 },
72
+ { label: "Child 2A", to: "/child-2a", rank: 1 },
73
+ ],
74
+ },
75
+ {
76
+ label: "Parent 1",
77
+ to: "/parent-1",
78
+ rank: 1,
79
+ items: [
80
+ { label: "Child 1C", to: "/child-1c", rank: 3 },
81
+ { label: "Child 1A", to: "/child-1a", rank: 1 },
82
+ { label: "Child 1B", to: "/child-1b", rank: 2 },
83
+ ],
84
+ },
85
+ ]
86
+
87
+ const sorted = sortMenuItemsByRank(items)
88
+
89
+ // Parents should be sorted
90
+ expect(sorted[0].label).toBe("Parent 1")
91
+ expect(sorted[1].label).toBe("Parent 2")
92
+
93
+ // Parent 1's children should be sorted
94
+ expect(sorted[0].items![0].label).toBe("Child 1A")
95
+ expect(sorted[0].items![1].label).toBe("Child 1B")
96
+ expect(sorted[0].items![2].label).toBe("Child 1C")
97
+
98
+ // Parent 2's children should be sorted
99
+ expect(sorted[1].items![0].label).toBe("Child 2A")
100
+ expect(sorted[1].items![1].label).toBe("Child 2B")
101
+ })
102
+
103
+ it("should handle nested items with mixed ranked and unranked", () => {
104
+ const items: INavItem[] = [
105
+ {
106
+ label: "Parent",
107
+ to: "/parent",
108
+ rank: 1,
109
+ items: [
110
+ { label: "No Rank Child", to: "/no-rank" },
111
+ { label: "Rank 1 Child", to: "/rank-1", rank: 1 },
112
+ { label: "Rank 2 Child", to: "/rank-2", rank: 2 },
113
+ ],
114
+ },
115
+ ]
116
+
117
+ const sorted = sortMenuItemsByRank(items)
118
+
119
+ expect(sorted[0].items![0].label).toBe("Rank 1 Child")
120
+ expect(sorted[0].items![1].label).toBe("Rank 2 Child")
121
+ expect(sorted[0].items![2].label).toBe("No Rank Child")
122
+ })
123
+
124
+ it("should handle empty items array", () => {
125
+ const items: INavItem[] = []
126
+
127
+ const sorted = sortMenuItemsByRank(items)
128
+
129
+ expect(sorted).toEqual([])
130
+ })
131
+
132
+ it("should handle single item", () => {
133
+ const items: INavItem[] = [{ label: "Only Item", to: "/only", rank: 1 }]
134
+
135
+ const sorted = sortMenuItemsByRank(items)
136
+
137
+ expect(sorted).toHaveLength(1)
138
+ expect(sorted[0].label).toBe("Only Item")
139
+ })
140
+
141
+ it("should preserve items without nested arrays", () => {
142
+ const items: INavItem[] = [
143
+ { label: "Item 1", to: "/item-1", rank: 2 },
144
+ { label: "Item 2", to: "/item-2", rank: 1 },
145
+ ]
146
+
147
+ const sorted = sortMenuItemsByRank(items)
148
+
149
+ expect(sorted[0].items).toBeUndefined()
150
+ expect(sorted[1].items).toBeUndefined()
151
+ })
152
+
153
+ it("should handle duplicate rank values", () => {
154
+ const items: INavItem[] = [
155
+ { label: "Item C", to: "/item-c", rank: 1 },
156
+ { label: "Item A", to: "/item-a", rank: 1 },
157
+ { label: "Item B", to: "/item-b", rank: 1 },
158
+ ]
159
+
160
+ const sorted = sortMenuItemsByRank(items)
161
+
162
+ // All should have rank 1, order should be stable
163
+ expect(sorted[0].rank).toBe(1)
164
+ expect(sorted[1].rank).toBe(1)
165
+ expect(sorted[2].rank).toBe(1)
166
+ expect(sorted).toHaveLength(3)
167
+ })
168
+ })
169
+
@@ -18,6 +18,7 @@ import { Providers } from "../providers"
18
18
  import coreTranslations from "../i18n/translations"
19
19
  import { getRouteMap } from "./routes/get-route.map"
20
20
  import { createRouteMap, getRouteExtensions } from "./routes/utils"
21
+ import { sortMenuItemsByRank } from "./utils/sort-menu-items-by-rank"
21
22
  import {
22
23
  ConfigExtension,
23
24
  ConfigField,
@@ -181,12 +182,13 @@ export class DashboardApp {
181
182
  return
182
183
  }
183
184
 
184
- const navItem: INavItem = {
185
+ const navItem: INavItem & { rank?: number } = {
185
186
  label: item.label,
186
187
  to: item.path,
187
188
  icon: item.icon ? <item.icon /> : undefined,
188
189
  items: [],
189
190
  nested: item.nested,
191
+ rank: item.rank,
190
192
  translationNs: item.translationNs,
191
193
  }
192
194
 
@@ -205,6 +207,12 @@ export class DashboardApp {
205
207
  tempRegistry[item.path] = navItem
206
208
  })
207
209
 
210
+ // Sort menu items by rank (ascending order, undefined ranks come last)
211
+ registry.forEach((items, key) => {
212
+ const sorted = sortMenuItemsByRank(items)
213
+ registry.set(key, sorted)
214
+ })
215
+
208
216
  return registry
209
217
  }
210
218
 
@@ -24,6 +24,7 @@ export type MenuItemExtension = {
24
24
  path: string
25
25
  icon?: ComponentType
26
26
  nested?: NestedRoutePosition
27
+ rank?: number
27
28
  translationNs?: string
28
29
  }
29
30
 
@@ -0,0 +1,43 @@
1
+ import { INavItem } from "../../components/layout/nav-item"
2
+
3
+ /**
4
+ * Sort menu items by rank in ascending order.
5
+ * Items with rank come first, sorted by rank value.
6
+ * Items without rank come last, maintaining their original order.
7
+ * Recursively sorts nested items independently.
8
+ */
9
+ export function sortMenuItemsByRank(
10
+ items: (INavItem & { rank?: number })[]
11
+ ): INavItem[] {
12
+ // Sort items by rank (ascending order)
13
+ // Items with rank come first, sorted by rank value
14
+ // Items without rank come last, maintaining their original order
15
+ const sortedItems = items.sort((a, b) => {
16
+ // If both have rank, sort by rank value
17
+ if (a.rank !== undefined && b.rank !== undefined) {
18
+ return a.rank - b.rank
19
+ }
20
+ // If only a has rank, it comes first
21
+ if (a.rank !== undefined) {
22
+ return -1
23
+ }
24
+ // If only b has rank, it comes first
25
+ if (b.rank !== undefined) {
26
+ return 1
27
+ }
28
+ // If neither has rank, maintain original order
29
+ return 0
30
+ })
31
+
32
+ // Recursively sort nested items
33
+ sortedItems.forEach((item) => {
34
+ if (item.items && item.items.length > 0) {
35
+ item.items = sortMenuItemsByRank(
36
+ item.items as (INavItem & { rank?: number })[]
37
+ )
38
+ }
39
+ })
40
+
41
+ return sortedItems
42
+ }
43
+