@eintrek/erp-shell 0.1.57 → 0.1.59
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/README.md +10 -0
- package/dist/help/help-store.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +156 -84
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +155 -82
- package/dist/index.js.map +1 -1
- package/dist/lib/plan-features.d.ts +4 -0
- package/dist/navigation/app-registry.d.ts +1 -1
- package/dist/navigation/navigation-data-helpers.d.ts +44 -9
- package/dist/navigation/navigation-types.d.ts +6 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -778,10 +778,23 @@ function longestMatch(path, modules) {
|
|
|
778
778
|
function getActiveModule(pathname, modules) {
|
|
779
779
|
return longestMatch(pathBelowCode(pathname), modules)?.module.id ?? null;
|
|
780
780
|
}
|
|
781
|
-
/**
|
|
781
|
+
/**
|
|
782
|
+
* Find the active sub-module id from `pathname`: the page whose own URL — or
|
|
783
|
+
* one of whose listed `subPages` — is the path itself (below the org code,
|
|
784
|
+
* ignoring a trailing slash). A record, a create or an edit page below a page
|
|
785
|
+
* is no page of the menu, so it has no active sub-module (0.1.58); the module
|
|
786
|
+
* (`getActiveModule`) still says where it belongs.
|
|
787
|
+
*
|
|
788
|
+
* Equal URLs in two modules go to the active module's page.
|
|
789
|
+
*/
|
|
782
790
|
function getActiveSubModule(pathname, modules) {
|
|
783
|
-
|
|
784
|
-
|
|
791
|
+
const path = strip(pathBelowCode(pathname));
|
|
792
|
+
const isPage = (url) => isMenuPath(url) && strip(url) === path;
|
|
793
|
+
const pagesOf = (m) => (m.subModules ?? []).filter(sub => isPage(sub.url) || (sub.subPages ?? []).some(p => isPage(p.url)));
|
|
794
|
+
const moduleId = getActiveModule(pathname, modules);
|
|
795
|
+
const own = modules.find(m => m.id === moduleId);
|
|
796
|
+
const hit = (own ? pagesOf(own)[0] : undefined) ?? modules.flatMap(pagesOf)[0];
|
|
797
|
+
return hit?.id ?? null;
|
|
785
798
|
}
|
|
786
799
|
/** Prepend `code` (org code) to a relative URL so `/sales` → `/O25.../sales`.
|
|
787
800
|
* Absolute `http(s)://` URLs are left intact; optional `{code}` placeholder is replaced.
|
|
@@ -804,100 +817,138 @@ function buildUrlWithCode(code, url) {
|
|
|
804
817
|
return `${base}${query}${hash}`;
|
|
805
818
|
}
|
|
806
819
|
const strip = (p) => (p.length > 1 ? p.replace(/\/+$/, "") : p);
|
|
820
|
+
/** A URL the path can be compared with: not query-only, not another site. */
|
|
821
|
+
const isMenuPath = (url) => !!url && !url.includes("?") && !/^https?:\/\//i.test(url);
|
|
807
822
|
/** Same check as `isPathActive`: the page itself or one below it. */
|
|
808
823
|
const pathIsAtOrBelow = (pathname, url) => pathname === url || pathname.startsWith(url + "/");
|
|
809
824
|
/** "/O1/" and "/O1" are the same page; a query string never is. */
|
|
810
825
|
function samePage(pathname, url) {
|
|
811
826
|
if (url.includes("?"))
|
|
812
827
|
return false;
|
|
813
|
-
return strip(pathname) === strip(url);
|
|
828
|
+
return strip(pathname.split("?")[0]) === strip(url);
|
|
814
829
|
}
|
|
815
830
|
/**
|
|
816
|
-
* How long
|
|
817
|
-
*
|
|
818
|
-
*
|
|
831
|
+
* How long `url` is when it is the page `pathname` shows (ignoring a trailing
|
|
832
|
+
* slash), or -1. Compared with and without the org code, as the menu URLs
|
|
833
|
+
* are written either way.
|
|
819
834
|
*/
|
|
820
|
-
function
|
|
835
|
+
function pageLength(pathname, url, code) {
|
|
836
|
+
if (!isMenuPath(url))
|
|
837
|
+
return -1;
|
|
821
838
|
const built = buildUrlWithCode(code, url);
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
839
|
+
if (samePage(pathname, built))
|
|
840
|
+
return strip(built).length;
|
|
841
|
+
if (samePage(pathname, url))
|
|
842
|
+
return strip(url).length;
|
|
843
|
+
return -1;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* How long the URL that makes `url` cover `pathname` is — the page itself or
|
|
847
|
+
* one below it — or -1. The organisation's home ("/" → "/O1") covers only
|
|
848
|
+
* itself: every page sits below it, and a dashboard is not the parent of
|
|
849
|
+
* every page.
|
|
850
|
+
*/
|
|
851
|
+
function coverLength(pathname, url, code) {
|
|
852
|
+
if (!isMenuPath(url))
|
|
853
|
+
return -1;
|
|
854
|
+
const path = strip(pathname.split("?")[0]);
|
|
855
|
+
const built = strip(buildUrlWithCode(code, url));
|
|
856
|
+
const isRoot = url === "/" || (!!code && built === `/${code}`);
|
|
857
|
+
if (isRoot)
|
|
858
|
+
return pageLength(path, url, code);
|
|
859
|
+
if (pathIsAtOrBelow(path, built))
|
|
829
860
|
return built.length;
|
|
830
|
-
|
|
831
|
-
|
|
861
|
+
const raw = strip(url);
|
|
862
|
+
if (pathIsAtOrBelow(path, raw))
|
|
863
|
+
return raw.length;
|
|
832
864
|
return -1;
|
|
833
865
|
}
|
|
834
866
|
/**
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
867
|
+
* Where `pathname` sits in the sidebar: the entry to light and the group to
|
|
868
|
+
* open.
|
|
869
|
+
*
|
|
870
|
+
* Lit (0.1.58): only the entry whose own page this is — its URL or one of its
|
|
871
|
+
* `subPages`, exactly. A record, a create or an edit page below a menu page
|
|
872
|
+
* (Plannex /project/detail/<id>/schedule under "โครงการ" /project) lights
|
|
873
|
+
* nothing; an app lists such a page in `subPages` when it should keep its
|
|
874
|
+
* entry lit. At most one entry across every group (0.1.57).
|
|
875
|
+
*
|
|
876
|
+
* Open: the lit entry's group, or else the group with the deepest URL the
|
|
877
|
+
* path sits below.
|
|
839
878
|
*
|
|
840
879
|
* Equal lengths go to the group the app marks active (`item.isActive`, from
|
|
841
880
|
* its `activeModule`), then to a page over a group row, then to the first in
|
|
842
881
|
* menu order.
|
|
843
882
|
*/
|
|
844
|
-
function
|
|
845
|
-
const path = pathname ?? "";
|
|
883
|
+
function resolveSidebarNav(items, pathname, { code, highlightActiveModule = false } = {}) {
|
|
884
|
+
const path = (pathname ?? "").split("?")[0];
|
|
846
885
|
// The app named a one-line module as the current one: that is the answer.
|
|
847
886
|
if (highlightActiveModule) {
|
|
848
887
|
const leaf = items.findIndex(item => !item.subModules?.length && !!item.isActive);
|
|
849
|
-
if (leaf >= 0)
|
|
850
|
-
return {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
if (!best) {
|
|
855
|
-
best = c;
|
|
856
|
-
return;
|
|
857
|
-
}
|
|
858
|
-
if (c.length !== best.length) {
|
|
859
|
-
if (c.length > best.length)
|
|
860
|
-
best = c;
|
|
861
|
-
return;
|
|
888
|
+
if (leaf >= 0) {
|
|
889
|
+
return {
|
|
890
|
+
active: { item: leaf, sub: null, subPage: null },
|
|
891
|
+
open: { item: leaf, sub: null },
|
|
892
|
+
};
|
|
862
893
|
}
|
|
894
|
+
}
|
|
895
|
+
const better = (c, best) => {
|
|
896
|
+
if (!best)
|
|
897
|
+
return true;
|
|
898
|
+
if (c.length !== best.length)
|
|
899
|
+
return c.length > best.length;
|
|
863
900
|
const cActive = !!items[c.item].isActive;
|
|
864
901
|
const bActive = !!items[best.item].isActive;
|
|
865
|
-
if (cActive !== bActive)
|
|
866
|
-
|
|
867
|
-
|
|
902
|
+
if (cActive !== bActive)
|
|
903
|
+
return cActive;
|
|
904
|
+
// The same sub-item by its own URL and by a listed page: the page.
|
|
905
|
+
if (c.item === best.item && c.sub === best.sub) {
|
|
906
|
+
return c.subPage !== null && best.subPage === null;
|
|
907
|
+
}
|
|
908
|
+
return c.sub !== null && best.sub === null;
|
|
909
|
+
};
|
|
910
|
+
let exact = null;
|
|
911
|
+
let within = null;
|
|
912
|
+
const consider = (c, isExact) => {
|
|
913
|
+
if (c.length < 0)
|
|
868
914
|
return;
|
|
915
|
+
if (isExact) {
|
|
916
|
+
if (better(c, exact))
|
|
917
|
+
exact = c;
|
|
918
|
+
}
|
|
919
|
+
else if (better(c, within)) {
|
|
920
|
+
within = c;
|
|
869
921
|
}
|
|
870
|
-
if (c.sub !== null && best.sub === null)
|
|
871
|
-
best = c;
|
|
872
922
|
};
|
|
873
923
|
items.forEach((item, i) => {
|
|
874
|
-
const itemUrl = buildUrlWithCode(code, item.url);
|
|
875
924
|
const subs = item.subModules ?? [];
|
|
925
|
+
const row = { item: i, sub: null, subPage: null };
|
|
876
926
|
// The row itself: only on its own URL. A one-line item under
|
|
877
927
|
// highlightActiveModule is lit by isActive alone (handled above).
|
|
878
928
|
if (!(highlightActiveModule && subs.length === 0)) {
|
|
879
|
-
|
|
880
|
-
if (own)
|
|
881
|
-
consider({ item: i, sub: null, subPage: null, length: strip(itemUrl).length });
|
|
929
|
+
consider({ ...row, length: pageLength(path, item.url, code) }, true);
|
|
882
930
|
}
|
|
931
|
+
consider({ ...row, length: coverLength(path, item.url, code) }, false);
|
|
883
932
|
subs.forEach((sub, j) => {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
933
|
+
const entry = { item: i, sub: j };
|
|
934
|
+
consider({ ...entry, subPage: null, length: pageLength(path, sub.url, code) }, true);
|
|
935
|
+
consider({ ...entry, subPage: null, length: coverLength(path, sub.url, code) }, false);
|
|
887
936
|
(sub.subPages ?? []).forEach((page, k) => {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
pageLength = l;
|
|
891
|
-
subPage = k;
|
|
892
|
-
}
|
|
937
|
+
consider({ ...entry, subPage: k, length: pageLength(path, page.url, code) }, true);
|
|
938
|
+
consider({ ...entry, subPage: k, length: coverLength(path, page.url, code) }, false);
|
|
893
939
|
});
|
|
894
|
-
const length = Math.max(coverLength(path, sub.url, code), pageLength);
|
|
895
|
-
if (length >= 0)
|
|
896
|
-
consider({ item: i, sub: j, subPage, length });
|
|
897
940
|
});
|
|
898
941
|
});
|
|
899
|
-
const
|
|
900
|
-
|
|
942
|
+
const lit = exact;
|
|
943
|
+
const holder = lit ?? within;
|
|
944
|
+
return {
|
|
945
|
+
active: lit ? { item: lit.item, sub: lit.sub, subPage: lit.subPage } : null,
|
|
946
|
+
open: holder ? { item: holder.item, sub: holder.sub } : null,
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
/** The entry lit for `pathname` — `resolveSidebarNav(...).active`. */
|
|
950
|
+
function resolveActiveNav(items, pathname, options = {}) {
|
|
951
|
+
return resolveSidebarNav(items, pathname, options).active;
|
|
901
952
|
}
|
|
902
953
|
|
|
903
954
|
function NavTools({ tools, closeOnNavigation = false }) {
|
|
@@ -1384,7 +1435,7 @@ function platformApiBase(app) {
|
|
|
1384
1435
|
* This package's version, attached to help messages so the back office can
|
|
1385
1436
|
* tell which shell a report came from. Keep in step with package.json.
|
|
1386
1437
|
*/
|
|
1387
|
-
const SHELL_VERSION = "0.1.
|
|
1438
|
+
const SHELL_VERSION = "0.1.59";
|
|
1388
1439
|
|
|
1389
1440
|
const HELP_APP_LABEL = {
|
|
1390
1441
|
platform: "แพลตฟอร์ม",
|
|
@@ -1392,6 +1443,8 @@ const HELP_APP_LABEL = {
|
|
|
1392
1443
|
peoplx: "Peoplx",
|
|
1393
1444
|
plannex: "Plannex",
|
|
1394
1445
|
invenx: "Invenx",
|
|
1446
|
+
sellx: "Sellx",
|
|
1447
|
+
carex: "Carex",
|
|
1395
1448
|
other: "อื่น ๆ",
|
|
1396
1449
|
};
|
|
1397
1450
|
function originOf(value) {
|
|
@@ -1426,6 +1479,10 @@ function detectHelpApp(explicit) {
|
|
|
1426
1479
|
return "plannex";
|
|
1427
1480
|
if (host.startsWith("invenx."))
|
|
1428
1481
|
return "invenx";
|
|
1482
|
+
if (host.startsWith("sellx."))
|
|
1483
|
+
return "sellx";
|
|
1484
|
+
if (host.startsWith("carex."))
|
|
1485
|
+
return "carex";
|
|
1429
1486
|
if (host.startsWith("platform.") || host === "antniti.com" || host === "www.antniti.com") {
|
|
1430
1487
|
return "platform";
|
|
1431
1488
|
}
|
|
@@ -1436,6 +1493,8 @@ function detectHelpApp(explicit) {
|
|
|
1436
1493
|
["invenx", process.env.NEXT_PUBLIC_INVENX_URL],
|
|
1437
1494
|
["plannex", process.env.NEXT_PUBLIC_PLANNEX_URL],
|
|
1438
1495
|
["peoplx", process.env.NEXT_PUBLIC_HR_URL],
|
|
1496
|
+
["sellx", process.env.NEXT_PUBLIC_SELLX_URL],
|
|
1497
|
+
["carex", process.env.NEXT_PUBLIC_CAREX_URL],
|
|
1439
1498
|
];
|
|
1440
1499
|
for (const [id, url] of configured) {
|
|
1441
1500
|
if (originOf(url) === here)
|
|
@@ -1823,6 +1882,10 @@ const PLAN_FEATURES = {
|
|
|
1823
1882
|
MODULE_INVENTORY: "module.inventory",
|
|
1824
1883
|
MODULE_PROJECT: "module.project",
|
|
1825
1884
|
MODULE_SECRETARIAT: "module.secretariat",
|
|
1885
|
+
/** Sellx add-on: POS, members and chat commerce. */
|
|
1886
|
+
MODULE_SELLX: "module.sellx",
|
|
1887
|
+
/** Carex add-on: help desk, SLA and knowledge base. */
|
|
1888
|
+
MODULE_CAREX: "module.carex",
|
|
1826
1889
|
/** AI pack (paid or trial): AI calls on AntNiti's key while credits remain. */
|
|
1827
1890
|
AI: "ai",
|
|
1828
1891
|
};
|
|
@@ -1907,6 +1970,20 @@ const APPS = [
|
|
|
1907
1970
|
features: [PLAN_FEATURES.MODULE_HR],
|
|
1908
1971
|
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_HR_URL, "https://peoplx.antniti.com"),
|
|
1909
1972
|
},
|
|
1973
|
+
{
|
|
1974
|
+
id: "sellx",
|
|
1975
|
+
label: "Sellx",
|
|
1976
|
+
icon: jsxRuntime.jsx(lucideReact.Store, { className: "h-4 w-4 shrink-0" }),
|
|
1977
|
+
features: [PLAN_FEATURES.MODULE_SELLX],
|
|
1978
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_SELLX_URL, "https://sellx.antniti.com"),
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
id: "carex",
|
|
1982
|
+
label: "Carex",
|
|
1983
|
+
icon: jsxRuntime.jsx(lucideReact.Headset, { className: "h-4 w-4 shrink-0" }),
|
|
1984
|
+
features: [PLAN_FEATURES.MODULE_CAREX],
|
|
1985
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_CAREX_URL, "https://carex.antniti.com"),
|
|
1986
|
+
},
|
|
1910
1987
|
];
|
|
1911
1988
|
/**
|
|
1912
1989
|
* Builds the cross-app link list for <NavUser systemLinks>.
|
|
@@ -1942,12 +2019,11 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
|
|
|
1942
2019
|
setOpen(false);
|
|
1943
2020
|
};
|
|
1944
2021
|
const code = orgCode ?? params?.code;
|
|
1945
|
-
// The one entry
|
|
1946
|
-
//
|
|
1947
|
-
//
|
|
1948
|
-
const active =
|
|
2022
|
+
// The one entry lit for this page — only on that entry's own page, never
|
|
2023
|
+
// on a record or a form below it — and the group holding the page, which
|
|
2024
|
+
// opens either way.
|
|
2025
|
+
const { active, open } = resolveSidebarNav(items, pathname, {
|
|
1949
2026
|
code,
|
|
1950
|
-
workspace,
|
|
1951
2027
|
highlightActiveModule,
|
|
1952
2028
|
});
|
|
1953
2029
|
const states = items.map((item, i) => {
|
|
@@ -1957,36 +2033,32 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
|
|
|
1957
2033
|
itemUrl,
|
|
1958
2034
|
activeSub: mine?.sub ?? null,
|
|
1959
2035
|
activeSubPage: mine?.subPage ?? null,
|
|
1960
|
-
|
|
2036
|
+
openSub: open?.item === i ? open.sub : null,
|
|
1961
2037
|
isItemActive: !!mine && mine.sub === null,
|
|
1962
2038
|
};
|
|
1963
2039
|
});
|
|
1964
|
-
// A group opens when
|
|
2040
|
+
// A group opens when the page moves into it and otherwise stays as the
|
|
1965
2041
|
// user left it. defaultOpen alone decided once, on the first render — and
|
|
1966
2042
|
// on a direct load the sub-items arrive after permissions do, so the group
|
|
1967
2043
|
// holding the current page stayed shut.
|
|
1968
|
-
const
|
|
1969
|
-
|
|
1970
|
-
.map(item => item.id)
|
|
1971
|
-
.join(",");
|
|
1972
|
-
const [openIds, setOpenIds] = React__namespace.useState(() => new Set(activeKey ? activeKey.split(",") : []));
|
|
2044
|
+
const openId = open ? (items[open.item]?.id ?? "") : "";
|
|
2045
|
+
const [openIds, setOpenIds] = React__namespace.useState(() => new Set(openId ? [openId] : []));
|
|
1973
2046
|
React__namespace.useEffect(() => {
|
|
1974
|
-
if (!
|
|
2047
|
+
if (!openId)
|
|
1975
2048
|
return;
|
|
1976
2049
|
setOpenIds(prev => {
|
|
1977
|
-
|
|
1978
|
-
if (ids.every(id => prev.has(id)))
|
|
2050
|
+
if (prev.has(openId))
|
|
1979
2051
|
return prev;
|
|
1980
2052
|
const next = new Set(prev);
|
|
1981
|
-
|
|
2053
|
+
next.add(openId);
|
|
1982
2054
|
return next;
|
|
1983
2055
|
});
|
|
1984
|
-
}, [
|
|
1985
|
-
const setItemOpen = (id,
|
|
1986
|
-
if (prev.has(id) ===
|
|
2056
|
+
}, [openId]);
|
|
2057
|
+
const setItemOpen = (id, isOpen) => setOpenIds(prev => {
|
|
2058
|
+
if (prev.has(id) === isOpen)
|
|
1987
2059
|
return prev;
|
|
1988
2060
|
const next = new Set(prev);
|
|
1989
|
-
if (
|
|
2061
|
+
if (isOpen)
|
|
1990
2062
|
next.add(id);
|
|
1991
2063
|
else
|
|
1992
2064
|
next.delete(id);
|
|
@@ -1997,7 +2069,7 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
|
|
|
1997
2069
|
item.group &&
|
|
1998
2070
|
item.group !== items[index - 1]?.group ? (jsxRuntime.jsx("li", { className: "list-none px-3 pb-2.5 text-xs text-muted-foreground" +
|
|
1999
2071
|
(index > 0 ? " pt-5" : ""), children: item.group }, `group-${item.id}`)) : null;
|
|
2000
|
-
const { itemUrl, activeSub, activeSubPage, isItemActive } = states[index];
|
|
2072
|
+
const { itemUrl, activeSub, activeSubPage, openSub, isItemActive } = states[index];
|
|
2001
2073
|
const IconComp = item.icon;
|
|
2002
2074
|
const workspaceButton = workspace
|
|
2003
2075
|
? "h-auto gap-3 rounded-[10px] px-3 py-2.5 text-xs " +
|
|
@@ -2007,7 +2079,7 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
|
|
|
2007
2079
|
: "";
|
|
2008
2080
|
const icon = workspace && IconComp ? (jsxRuntime.jsx(IconComp, { className: "size-[18px] shrink-0" })) : null;
|
|
2009
2081
|
const badge = workspace && item.badge !== undefined && item.badge !== "" ? (jsxRuntime.jsx("span", { className: "ml-auto min-w-5 rounded-[5px] bg-primary/15 px-1 text-center text-xs leading-5 font-bold tabular-nums text-primary", children: item.badge })) : null;
|
|
2010
|
-
return (jsxRuntime.jsxs(React__namespace.Fragment, { children: [groupHeading, jsxRuntime.jsx(erpTheme.Collapsible, { asChild: true, open: openIds.has(item.id), onOpenChange:
|
|
2082
|
+
return (jsxRuntime.jsxs(React__namespace.Fragment, { children: [groupHeading, jsxRuntime.jsx(erpTheme.Collapsible, { asChild: true, open: openIds.has(item.id), onOpenChange: isOpen => setItemOpen(item.id, isOpen), className: "group/collapsible", children: jsxRuntime.jsxs(SidebarMenuItem, { children: [jsxRuntime.jsx(erpTheme.CollapsibleTrigger, { asChild: true, children: jsxRuntime.jsx(SidebarMenuButton, { asChild: !item.subModules || item.subModules.length === 0, isActive: isItemActive, className: "data-[state=open]:text-sidebar-accent-foreground " +
|
|
2011
2083
|
workspaceButton, children: item.subModules && item.subModules.length > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [icon, jsxRuntime.jsx("span", { id: item.id, children: item.titleTh }), jsxRuntime.jsx(lucideReact.ChevronRight, { className: "ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" })] })) : (jsxRuntime.jsxs(Link, { href: itemUrl, prefetch: false, className: "flex items-center w-full min-w-0 flex-1 " +
|
|
2012
2084
|
(workspace ? "gap-3" : "gap-2"), onClick: handleNavLinkClick, "aria-current": isItemActive ? "page" : undefined, children: [icon, jsxRuntime.jsx("span", { id: item.id, className: "flex-1 truncate", title: item.titleTh, children: item.titleTh }), badge] })) }) }), item.subModules && item.subModules.length > 0 && (jsxRuntime.jsx(erpTheme.CollapsibleContent, { children: jsxRuntime.jsx(SidebarMenuSub, { className: workspace
|
|
2013
2085
|
? "mx-0 mt-1 mb-3 ml-[21px] gap-0.5 border-l border-sidebar-border pl-2.5 [&_a]:h-auto [&_a]:gap-[11px] [&_a]:px-3 [&_a]:py-2 [&_a]:text-xs [&_svg]:!size-[17px]"
|
|
@@ -2021,7 +2093,7 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
|
|
|
2021
2093
|
if (subItem.isCollapsible &&
|
|
2022
2094
|
subItem.subPages &&
|
|
2023
2095
|
subItem.subPages.length > 0) {
|
|
2024
|
-
return (jsxRuntime.jsx(erpTheme.Collapsible, { asChild: true, defaultOpen: isSubItemActive, className: "group/sub-collapsible", children: jsxRuntime.jsxs(SidebarMenuSubItem, { children: [jsxRuntime.jsx(erpTheme.CollapsibleTrigger, { asChild: true, children: jsxRuntime.jsxs(SidebarMenuSubButton, { className: "w-full", isActive: isSubItemActive, children: [SubIcon && (jsxRuntime.jsx(SubIcon, { className: "sidebar-submodule-icon flex-shrink-0" })), jsxRuntime.jsx("span", { className: "flex-1 truncate", title: subItem.titleTh, children: subItem.titleTh }), jsxRuntime.jsx(lucideReact.ChevronDown, { className: "ml-auto size-4 transition-transform duration-200 group-data-[state=open]/sub-collapsible:rotate-180" })] }) }), jsxRuntime.jsx(erpTheme.CollapsibleContent, { children: jsxRuntime.jsx(SidebarMenuSub, { className: "ml-4", children: subItem.subPages.map((subPage, subPageIndex) => {
|
|
2096
|
+
return (jsxRuntime.jsx(erpTheme.Collapsible, { asChild: true, defaultOpen: isSubItemActive || openSub === subIndex, className: "group/sub-collapsible", children: jsxRuntime.jsxs(SidebarMenuSubItem, { children: [jsxRuntime.jsx(erpTheme.CollapsibleTrigger, { asChild: true, children: jsxRuntime.jsxs(SidebarMenuSubButton, { className: "w-full", isActive: isSubItemActive, children: [SubIcon && (jsxRuntime.jsx(SubIcon, { className: "sidebar-submodule-icon flex-shrink-0" })), jsxRuntime.jsx("span", { className: "flex-1 truncate", title: subItem.titleTh, children: subItem.titleTh }), jsxRuntime.jsx(lucideReact.ChevronDown, { className: "ml-auto size-4 transition-transform duration-200 group-data-[state=open]/sub-collapsible:rotate-180" })] }) }), jsxRuntime.jsx(erpTheme.CollapsibleContent, { children: jsxRuntime.jsx(SidebarMenuSub, { className: "ml-4", children: subItem.subPages.map((subPage, subPageIndex) => {
|
|
2025
2097
|
const subPageUrl = buildUrlWithCode(code, subPage.url);
|
|
2026
2098
|
const isSubPageActive = isSubItemActive &&
|
|
2027
2099
|
activeSubPage === subPageIndex;
|
|
@@ -3810,6 +3882,7 @@ exports.normalizePathnameForPermissionRules = normalizePathnameForPermissionRule
|
|
|
3810
3882
|
exports.openHelp = openHelp;
|
|
3811
3883
|
exports.parseMyRoles = parseMyRoles;
|
|
3812
3884
|
exports.resolveActiveNav = resolveActiveNav;
|
|
3885
|
+
exports.resolveSidebarNav = resolveSidebarNav;
|
|
3813
3886
|
exports.resolveUiRoutePermission = resolveUiRoutePermission;
|
|
3814
3887
|
exports.roleSummary = roleSummary;
|
|
3815
3888
|
exports.runGlobalRequestPrecheck = runGlobalRequestPrecheck;
|