@medusajs/dashboard 2.11.4-snapshot-20251107205323 → 2.11.4-snapshot-20251107211311
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 +35 -0
- package/dist/app.mjs +1 -1
- package/dist/{chunk-G5IQN3U5.mjs → chunk-TOC5EBTT.mjs} +36 -7
- package/dist/{chunk-5N4LN27X.mjs → chunk-UKW3OFAT.mjs} +1 -1
- package/dist/{product-attributes-7DOF3KZM.mjs → product-attributes-FUUM7Q3L.mjs} +2 -2
- package/dist/{product-create-XHUQIPPD.mjs → product-create-EGQR452M.mjs} +1 -1
- package/dist/{product-detail-XMENUWZD.mjs → product-detail-6NSJSQHE.mjs} +2 -2
- package/dist/{product-edit-ZGJ7ZMYO.mjs → product-edit-PLDW25LJ.mjs} +2 -2
- package/dist/{product-organization-IIFOIFRY.mjs → product-organization-3GZG6Y35.mjs} +2 -2
- package/dist/{product-shipping-profile-ACSGG74B.mjs → product-shipping-profile-O64BAU3X.mjs} +2 -2
- package/package.json +9 -9
- package/src/dashboard-app/__tests__/sort-menu-items-by-rank.spec.ts +169 -0
- package/src/dashboard-app/dashboard-app.tsx +9 -1
- package/src/dashboard-app/types.ts +1 -0
- package/src/dashboard-app/utils/sort-menu-items-by-rank.ts +43 -0
package/dist/app.js
CHANGED
|
@@ -188042,6 +188042,35 @@ var init_utils14 = __esm({
|
|
|
188042
188042
|
}
|
|
188043
188043
|
});
|
|
188044
188044
|
|
|
188045
|
+
// src/dashboard-app/utils/sort-menu-items-by-rank.ts
|
|
188046
|
+
function sortMenuItemsByRank(items) {
|
|
188047
|
+
const sortedItems = items.sort((a, b) => {
|
|
188048
|
+
if (a.rank !== void 0 && b.rank !== void 0) {
|
|
188049
|
+
return a.rank - b.rank;
|
|
188050
|
+
}
|
|
188051
|
+
if (a.rank !== void 0) {
|
|
188052
|
+
return -1;
|
|
188053
|
+
}
|
|
188054
|
+
if (b.rank !== void 0) {
|
|
188055
|
+
return 1;
|
|
188056
|
+
}
|
|
188057
|
+
return 0;
|
|
188058
|
+
});
|
|
188059
|
+
sortedItems.forEach((item) => {
|
|
188060
|
+
if (item.items && item.items.length > 0) {
|
|
188061
|
+
item.items = sortMenuItemsByRank(
|
|
188062
|
+
item.items
|
|
188063
|
+
);
|
|
188064
|
+
}
|
|
188065
|
+
});
|
|
188066
|
+
return sortedItems;
|
|
188067
|
+
}
|
|
188068
|
+
var init_sort_menu_items_by_rank = __esm({
|
|
188069
|
+
"src/dashboard-app/utils/sort-menu-items-by-rank.ts"() {
|
|
188070
|
+
"use strict";
|
|
188071
|
+
}
|
|
188072
|
+
});
|
|
188073
|
+
|
|
188045
188074
|
// src/dashboard-app/dashboard-app.tsx
|
|
188046
188075
|
var import_admin_shared, import_react_router_dom247, import_jsx_runtime684, OPTIONAL_LAST_SEGMENT_MATCH, DashboardApp;
|
|
188047
188076
|
var init_dashboard_app = __esm({
|
|
@@ -188053,6 +188082,7 @@ var init_dashboard_app = __esm({
|
|
|
188053
188082
|
init_translations();
|
|
188054
188083
|
init_get_route_map();
|
|
188055
188084
|
init_utils14();
|
|
188085
|
+
init_sort_menu_items_by_rank();
|
|
188056
188086
|
import_jsx_runtime684 = require("react/jsx-runtime");
|
|
188057
188087
|
OPTIONAL_LAST_SEGMENT_MATCH = /\/([^\/])+\?$/;
|
|
188058
188088
|
DashboardApp = class {
|
|
@@ -188162,6 +188192,7 @@ var init_dashboard_app = __esm({
|
|
|
188162
188192
|
icon: item.icon ? /* @__PURE__ */ (0, import_jsx_runtime684.jsx)(item.icon, {}) : void 0,
|
|
188163
188193
|
items: [],
|
|
188164
188194
|
nested: item.nested,
|
|
188195
|
+
rank: item.rank,
|
|
188165
188196
|
translationNs: item.translationNs
|
|
188166
188197
|
};
|
|
188167
188198
|
if (parentPath !== "/" && tempRegistry[parentPath]) {
|
|
@@ -188177,6 +188208,10 @@ var init_dashboard_app = __esm({
|
|
|
188177
188208
|
}
|
|
188178
188209
|
tempRegistry[item.path] = navItem;
|
|
188179
188210
|
});
|
|
188211
|
+
registry.forEach((items, key) => {
|
|
188212
|
+
const sorted = sortMenuItemsByRank(items);
|
|
188213
|
+
registry.set(key, sorted);
|
|
188214
|
+
});
|
|
188180
188215
|
return registry;
|
|
188181
188216
|
}
|
|
188182
188217
|
populateForm(plugins) {
|
package/dist/app.mjs
CHANGED
|
@@ -92515,7 +92515,7 @@ function getRouteMap({
|
|
|
92515
92515
|
children: [
|
|
92516
92516
|
{
|
|
92517
92517
|
path: "create",
|
|
92518
|
-
lazy: () => import("./product-create-
|
|
92518
|
+
lazy: () => import("./product-create-EGQR452M.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-
|
|
92534
|
+
const { Breadcrumb, loader } = await import("./product-detail-6NSJSQHE.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-
|
|
92546
|
+
lazy: () => import("./product-detail-6NSJSQHE.mjs"),
|
|
92547
92547
|
children: [
|
|
92548
92548
|
{
|
|
92549
92549
|
path: "edit",
|
|
92550
|
-
lazy: () => import("./product-edit-
|
|
92550
|
+
lazy: () => import("./product-edit-PLDW25LJ.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-
|
|
92562
|
+
lazy: () => import("./product-attributes-FUUM7Q3L.mjs")
|
|
92563
92563
|
},
|
|
92564
92564
|
{
|
|
92565
92565
|
path: "organization",
|
|
92566
|
-
lazy: () => import("./product-organization-
|
|
92566
|
+
lazy: () => import("./product-organization-3GZG6Y35.mjs")
|
|
92567
92567
|
},
|
|
92568
92568
|
{
|
|
92569
92569
|
path: "shipping-profile",
|
|
92570
|
-
lazy: () => import("./product-shipping-profile-
|
|
92570
|
+
lazy: () => import("./product-shipping-profile-O64BAU3X.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-
|
|
15
|
+
} from "./chunk-UKW3OFAT.mjs";
|
|
16
16
|
import {
|
|
17
17
|
FormExtensionZone,
|
|
18
18
|
useExtendableForm
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-TOC5EBTT.mjs";
|
|
20
20
|
import "./chunk-2SSUH2HJ.mjs";
|
|
21
21
|
import "./chunk-ONB3JEHR.mjs";
|
|
22
22
|
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-
|
|
31
|
-
import "./chunk-
|
|
30
|
+
} from "./chunk-UKW3OFAT.mjs";
|
|
31
|
+
import "./chunk-TOC5EBTT.mjs";
|
|
32
32
|
import "./chunk-2SSUH2HJ.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-
|
|
18
|
+
} from "./chunk-UKW3OFAT.mjs";
|
|
19
19
|
import {
|
|
20
20
|
FormExtensionZone,
|
|
21
21
|
useExtendableForm
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-TOC5EBTT.mjs";
|
|
23
23
|
import "./chunk-2SSUH2HJ.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-
|
|
20
|
+
} from "./chunk-UKW3OFAT.mjs";
|
|
21
21
|
import {
|
|
22
22
|
FormExtensionZone,
|
|
23
23
|
useExtendableForm
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TOC5EBTT.mjs";
|
|
25
25
|
import "./chunk-2SSUH2HJ.mjs";
|
|
26
26
|
import "./chunk-ONB3JEHR.mjs";
|
|
27
27
|
import "./chunk-YCDDT44O.mjs";
|
package/dist/{product-shipping-profile-ACSGG74B.mjs → product-shipping-profile-O64BAU3X.mjs}
RENAMED
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
} from "./chunk-AERWK3TJ.mjs";
|
|
15
15
|
import {
|
|
16
16
|
PRODUCT_DETAIL_FIELDS
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-UKW3OFAT.mjs";
|
|
18
|
+
import "./chunk-TOC5EBTT.mjs";
|
|
19
19
|
import "./chunk-2SSUH2HJ.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-snapshot-
|
|
3
|
+
"version": "2.11.4-snapshot-20251107211311",
|
|
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-snapshot-
|
|
50
|
-
"@medusajs/icons": "2.11.4-snapshot-
|
|
51
|
-
"@medusajs/js-sdk": "2.11.4-snapshot-
|
|
52
|
-
"@medusajs/ui": "4.0.28-snapshot-
|
|
49
|
+
"@medusajs/admin-shared": "2.11.4-snapshot-20251107211311",
|
|
50
|
+
"@medusajs/icons": "2.11.4-snapshot-20251107211311",
|
|
51
|
+
"@medusajs/js-sdk": "2.11.4-snapshot-20251107211311",
|
|
52
|
+
"@medusajs/ui": "4.0.28-snapshot-20251107211311",
|
|
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-snapshot-
|
|
85
|
-
"@medusajs/admin-vite-plugin": "2.11.4-snapshot-
|
|
86
|
-
"@medusajs/types": "2.11.4-snapshot-
|
|
87
|
-
"@medusajs/ui-preset": "2.11.4-snapshot-
|
|
84
|
+
"@medusajs/admin-shared": "2.11.4-snapshot-20251107211311",
|
|
85
|
+
"@medusajs/admin-vite-plugin": "2.11.4-snapshot-20251107211311",
|
|
86
|
+
"@medusajs/types": "2.11.4-snapshot-20251107211311",
|
|
87
|
+
"@medusajs/ui-preset": "2.11.4-snapshot-20251107211311"
|
|
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
|
|
|
@@ -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
|
+
|